]> git.lizzy.rs Git - rust.git/commitdiff
Implement volatile_load and volatile_store intrinsics.
authorPeter Zotov <whitequark@whitequark.org>
Sat, 28 Dec 2013 14:01:53 +0000 (18:01 +0400)
committerPeter Zotov <whitequark@whitequark.org>
Mon, 30 Dec 2013 22:54:25 +0000 (02:54 +0400)
src/librustc/lib/llvm.rs
src/librustc/middle/trans/build.rs
src/librustc/middle/trans/builder.rs
src/librustc/middle/trans/intrinsic.rs
src/librustc/middle/typeck/check/mod.rs
src/libstd/unstable/intrinsics.rs
src/test/run-make/volatile-intrinsics/Makefile [new file with mode: 0644]
src/test/run-make/volatile-intrinsics/main.rs [new file with mode: 0644]

index 50a35e9d1bf81f7de36ed6e671de1036d65dcec5..ae90acd3cb713f524aab5626492726c0b50734a9 100644 (file)
@@ -787,6 +787,10 @@ pub fn LLVMSetInstrParamAlignment(Instr: ValueRef,
         pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool;
         pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool);
 
+        /* Operations on load/store instructions (only) */
+        pub fn LLVMGetVolatile(MemoryAccessInst: ValueRef) -> Bool;
+        pub fn LLVMSetVolatile(MemoryAccessInst: ValueRef, volatile: Bool);
+
         /* Operations on phi nodes */
         pub fn LLVMAddIncoming(PhiNode: ValueRef,
                                IncomingValues: *ValueRef,
index faf210c1a9ea0c373b746697055406051c2e23a4..7a0e319e505016d63e93b284e0c86946888c3a9e 100644 (file)
@@ -349,6 +349,13 @@ pub fn Load(cx: &Block, PointerVal: ValueRef) -> ValueRef {
     }
 }
 
+pub fn VolatileLoad(cx: &Block, PointerVal: ValueRef) -> ValueRef {
+    unsafe {
+        if cx.unreachable.get() { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
+        B(cx).volatile_load(PointerVal)
+    }
+}
+
 pub fn AtomicLoad(cx: &Block, PointerVal: ValueRef, order: AtomicOrdering) -> ValueRef {
     unsafe {
         let ccx = cx.fcx.ccx;
@@ -383,6 +390,11 @@ pub fn Store(cx: &Block, Val: ValueRef, Ptr: ValueRef) {
     B(cx).store(Val, Ptr)
 }
 
+pub fn VolatileStore(cx: &Block, Val: ValueRef, Ptr: ValueRef) {
+    if cx.unreachable.get() { return; }
+    B(cx).volatile_store(Val, Ptr)
+}
+
 pub fn AtomicStore(cx: &Block, Val: ValueRef, Ptr: ValueRef, order: AtomicOrdering) {
     if cx.unreachable.get() { return; }
     B(cx).atomic_store(Val, Ptr, order)
index eacc6f84db11874ffa25942299a3a330e12a85f7..c4beb935ffecfc96512fe3454f809a99aa00bb38 100644 (file)
@@ -449,6 +449,15 @@ pub fn load(&self, ptr: ValueRef) -> ValueRef {
         }
     }
 
+    pub fn volatile_load(&self, ptr: ValueRef) -> ValueRef {
+        self.count_insn("load.volatile");
+        unsafe {
+            let insn = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
+            llvm::LLVMSetVolatile(insn, lib::llvm::True);
+            insn
+        }
+    }
+
     pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering) -> ValueRef {
         self.count_insn("load.atomic");
         unsafe {
@@ -488,6 +497,18 @@ pub fn store(&self, val: ValueRef, ptr: ValueRef) {
         }
     }
 
+    pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) {
+        debug!("Store {} -> {}",
+               self.ccx.tn.val_to_str(val),
+               self.ccx.tn.val_to_str(ptr));
+        assert!(is_not_null(self.llbuilder));
+        self.count_insn("store.volatile");
+        unsafe {
+            let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
+            llvm::LLVMSetVolatile(insn, lib::llvm::True);
+        }
+    }
+
     pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
         debug!("Store {} -> {}",
                self.ccx.tn.val_to_str(val),
index 02df3ff9c2046f380a6dbfbc8106d4957211bf63..f652fbec228cccd54474e124977e47acdf85da77 100644 (file)
@@ -73,6 +73,23 @@ fn with_overflow_instrinsic(bcx: @Block, name: &'static str, t: ty::t) {
         }
     }
 
+    fn volatile_load_intrinsic(bcx: @Block) {
+        let first_real_arg = bcx.fcx.arg_pos(0u);
+        let src = get_param(bcx.fcx.llfn, first_real_arg);
+
+        let val = VolatileLoad(bcx, src);
+        Ret(bcx, val);
+    }
+
+    fn volatile_store_intrinsic(bcx: @Block) {
+        let first_real_arg = bcx.fcx.arg_pos(0u);
+        let dst = get_param(bcx.fcx.llfn, first_real_arg);
+        let val = get_param(bcx.fcx.llfn, first_real_arg + 1);
+
+        VolatileStore(bcx, val, dst);
+        RetVoid(bcx);
+    }
+
     fn copy_intrinsic(bcx: @Block, allow_overlap: bool, tp_ty: ty::t) {
         let ccx = bcx.ccx();
         let lltp_ty = type_of::type_of(ccx, tp_ty);
@@ -480,6 +497,9 @@ fn count_zeros_intrinsic(bcx: @Block, name: &'static str) {
         "bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
         "bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
 
+        "volatile_load" => volatile_load_intrinsic(bcx),
+        "volatile_store" => volatile_store_intrinsic(bcx),
+
         "i8_add_with_overflow" =>
             with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i8", output_type),
         "i16_add_with_overflow" =>
index 74575ba3517fe6ac671a23be5a2c64d0d2e0c4c3..ef968d5cf36606764e8b15120eb66af84e7f3a2e 100644 (file)
@@ -4226,6 +4226,11 @@ fn param(ccx: @CrateCtxt, n: uint) -> ty::t {
             "bswap32"      => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
             "bswap64"      => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
 
+            "volatile_load" =>
+                (1, ~[ ty::mk_imm_ptr(tcx, param(ccx, 0)) ], param(ccx, 0)),
+            "volatile_store" =>
+                (1, ~[ ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ], ty::mk_nil()),
+
             "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
                 (0, ~[ty::mk_i8(), ty::mk_i8()],
                 ty::mk_tup(tcx, ~[ty::mk_i8(), ty::mk_bool()])),
index d3649f0285caa221c98dac1df5faef36c395e537..46dc03e82b0b825a49f27b1ef6bf9b14528eecba 100644 (file)
 
 The corresponding definitions are in librustc/middle/trans/foreign.rs.
 
+# Volatiles
+
+The volatile intrinsics provide operations intended to act on I/O
+memory, which are guaranteed to not be reordered by the compiler
+across other volatile intrinsics. See the LLVM documentation on
+[[volatile]].
+
+[volatile]: http://llvm.org/docs/LangRef.html#volatile-memory-accesses
+
 # Atomics
 
 The atomic intrinsics provide common atomic operations on machine
@@ -179,6 +188,9 @@ fn visit_leave_fn(&mut self, purity: uint, proto: uint,
     /// Execute a breakpoint trap, for inspection by a debugger.
     pub fn breakpoint();
 
+    #[cfg(not(stage0))] pub fn volatile_load<T>(src: *T) -> T;
+    #[cfg(not(stage0))] pub fn volatile_store<T>(dst: *mut T, val: T);
+
     /// Atomic compare and exchange, sequentially consistent.
     pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int;
     /// Atomic compare and exchange, acquire ordering.
diff --git a/src/test/run-make/volatile-intrinsics/Makefile b/src/test/run-make/volatile-intrinsics/Makefile
new file mode 100644 (file)
index 0000000..fc19412
--- /dev/null
@@ -0,0 +1,10 @@
+-include ../tools.mk
+
+all:
+       # The tests must pass...
+       $(RUSTC) main.rs
+       $(call RUN,main)
+       # ... and the loads/stores must not be optimized out.
+       $(RUSTC) main.rs --emit-llvm -S
+       grep "load volatile"  $(TMPDIR)/main.ll
+       grep "store volatile" $(TMPDIR)/main.ll
diff --git a/src/test/run-make/volatile-intrinsics/main.rs b/src/test/run-make/volatile-intrinsics/main.rs
new file mode 100644 (file)
index 0000000..5011a75
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::unstable::intrinsics::{volatile_load, volatile_store};
+
+pub fn main() {
+    unsafe {
+        let mut i : int = 1;
+        volatile_store(&mut i, 2);
+        assert_eq!(volatile_load(&i), 2);
+    }
+}