Skip to content

Commit c8a93ef

Browse files
committed
Merge remote-tracking branch 'remotes/origin/master' into cleanup-iterators
2 parents 5b2c1c5 + 2ba36ec commit c8a93ef

File tree

8 files changed

+268
-17
lines changed

8 files changed

+268
-17
lines changed

src/libextra/sync.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ impl WaitQueue {
7272
}
7373
count
7474
}
75+
76+
fn wait_end(&self) -> WaitEnd {
77+
let (wait_end, signal_end) = comm::oneshot();
78+
self.tail.send_deferred(signal_end);
79+
wait_end
80+
}
7581
}
7682

7783
// The building-block used to make semaphores, mutexes, and rwlocks.
@@ -100,12 +106,9 @@ impl<Q:Send> Sem<Q> {
100106
do (**self).with |state| {
101107
state.count -= 1;
102108
if state.count < 0 {
103-
// Create waiter nobe.
104-
let (WaitEnd, SignalEnd) = comm::oneshot();
105-
// Tell outer scope we need to block.
106-
waiter_nobe = Some(WaitEnd);
107-
// Enqueue ourself.
108-
state.waiters.tail.send_deferred(SignalEnd);
109+
// Create waiter nobe, enqueue ourself, and tell
110+
// outer scope we need to block.
111+
waiter_nobe = Some(state.waiters.wait_end());
109112
}
110113
}
111114
// Uncomment if you wish to test for sem races. Not valgrind-friendly.
@@ -201,10 +204,7 @@ impl<'self> Condvar<'self> {
201204
* wait() is equivalent to wait_on(0).
202205
*/
203206
pub fn wait_on(&self, condvar_id: uint) {
204-
// Create waiter nobe.
205-
let (WaitEnd, SignalEnd) = comm::oneshot();
206-
let mut WaitEnd = Some(WaitEnd);
207-
let mut SignalEnd = Some(SignalEnd);
207+
let mut WaitEnd = None;
208208
let mut out_of_bounds = None;
209209
do task::unkillable {
210210
// Release lock, 'atomically' enqueuing ourselves in so doing.
@@ -216,9 +216,9 @@ impl<'self> Condvar<'self> {
216216
if state.count <= 0 {
217217
state.waiters.signal();
218218
}
219-
// Enqueue ourself to be woken up by a signaller.
220-
let SignalEnd = SignalEnd.take_unwrap();
221-
state.blocked[condvar_id].tail.send_deferred(SignalEnd);
219+
// Create waiter nobe, and enqueue ourself to
220+
// be woken up by a signaller.
221+
WaitEnd = Some(state.blocked[condvar_id].wait_end());
222222
} else {
223223
out_of_bounds = Some(state.blocked.len());
224224
}

src/librustc/lib/llvm.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,8 @@ pub mod llvm {
15531553
/* Selected entries from the downcasts. */
15541554
#[fast_ffi]
15551555
pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef;
1556+
#[fast_ffi]
1557+
pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef;
15561558

15571559
/** Writes a module to the specified path. Returns 0 on success. */
15581560
#[fast_ffi]

src/librustc/middle/trans/base.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ use middle::trans::monomorphize;
5959
use middle::trans::tvec;
6060
use middle::trans::type_of;
6161
use middle::trans::type_of::*;
62+
use middle::trans::value::Value;
6263
use middle::ty;
6364
use util::common::indenter;
6465
use util::ppaux::{Repr, ty_to_str};
@@ -1792,11 +1793,30 @@ pub fn finish_fn(fcx: @mut FunctionContext, last_bcx: @mut Block) {
17921793
// Builds the return block for a function.
17931794
pub fn build_return_block(fcx: &FunctionContext, ret_cx: @mut Block) {
17941795
// Return the value if this function immediate; otherwise, return void.
1795-
if fcx.llretptr.is_some() && fcx.has_immediate_return_value {
1796-
Ret(ret_cx, Load(ret_cx, fcx.llretptr.unwrap()))
1797-
} else {
1798-
RetVoid(ret_cx)
1796+
if fcx.llretptr.is_none() || !fcx.has_immediate_return_value {
1797+
return RetVoid(ret_cx);
17991798
}
1799+
1800+
let retptr = Value(fcx.llretptr.unwrap());
1801+
let retval = match retptr.get_dominating_store(ret_cx) {
1802+
// If there's only a single store to the ret slot, we can directly return
1803+
// the value that was stored and omit the store and the alloca
1804+
Some(s) => {
1805+
let retval = *s.get_operand(0).unwrap();
1806+
s.erase_from_parent();
1807+
1808+
if retptr.has_no_uses() {
1809+
retptr.erase_from_parent();
1810+
}
1811+
1812+
retval
1813+
}
1814+
// Otherwise, load the return value from the ret slot
1815+
None => Load(ret_cx, fcx.llretptr.unwrap())
1816+
};
1817+
1818+
1819+
Ret(ret_cx, retval);
18001820
}
18011821

18021822
pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, }
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use lib::llvm::{llvm, BasicBlockRef};
12+
use middle::trans::value::{UserIterator, Value};
13+
use std::iterator::{Filter, Map};
14+
15+
pub struct BasicBlock(BasicBlockRef);
16+
17+
pub type PredIterator<'self> = Map<'self, Value, BasicBlock, Filter<'self, Value, UserIterator>>;
18+
19+
/**
20+
* Wrapper for LLVM BasicBlockRef
21+
*/
22+
impl BasicBlock {
23+
pub fn as_value(self) -> Value {
24+
unsafe {
25+
Value(llvm::LLVMBasicBlockAsValue(*self))
26+
}
27+
}
28+
29+
pub fn pred_iter(self) -> PredIterator {
30+
self.as_value().user_iter()
31+
.filter(|user| user.is_a_terminator_inst())
32+
.map(|user| user.get_parent().unwrap())
33+
}
34+
35+
pub fn get_single_predecessor(self) -> Option<BasicBlock> {
36+
let mut iter = self.pred_iter();
37+
match (iter.next(), iter.next()) {
38+
(Some(first), None) => Some(first),
39+
_ => None
40+
}
41+
}
42+
}

src/librustc/middle/trans/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ pub mod machine;
4242
pub mod adt;
4343
pub mod asm;
4444
pub mod type_;
45+
pub mod value;
46+
pub mod basic_block;

src/librustc/middle/trans/value.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use lib::llvm::{llvm, UseRef, ValueRef};
12+
use middle::trans::basic_block::BasicBlock;
13+
use middle::trans::common::Block;
14+
use std::libc::c_uint;
15+
16+
pub struct Value(ValueRef);
17+
18+
macro_rules! opt_val ( ($e:expr) => (
19+
unsafe {
20+
match $e {
21+
p if p.is_not_null() => Some(Value(p)),
22+
_ => None
23+
}
24+
}
25+
))
26+
27+
/**
28+
* Wrapper for LLVM ValueRef
29+
*/
30+
impl Value {
31+
/// Returns the BasicBlock that contains this value
32+
pub fn get_parent(self) -> Option<BasicBlock> {
33+
unsafe {
34+
match llvm::LLVMGetInstructionParent(*self) {
35+
p if p.is_not_null() => Some(BasicBlock(p)),
36+
_ => None
37+
}
38+
}
39+
}
40+
41+
/// Removes this value from its containing BasicBlock
42+
pub fn erase_from_parent(self) {
43+
unsafe {
44+
llvm::LLVMInstructionEraseFromParent(*self);
45+
}
46+
}
47+
48+
/// Returns the single dominating store to this value, if any
49+
/// This only performs a search for a trivially dominating store. The store
50+
/// must be the only user of this value, and there must not be any conditional
51+
/// branches between the store and the given block.
52+
pub fn get_dominating_store(self, bcx: @mut Block) -> Option<Value> {
53+
match self.get_single_user().chain(|user| user.as_store_inst()) {
54+
Some(store) => {
55+
do store.get_parent().chain |store_bb| {
56+
let mut bb = BasicBlock(bcx.llbb);
57+
let mut ret = Some(store);
58+
while *bb != *store_bb {
59+
match bb.get_single_predecessor() {
60+
Some(pred) => bb = pred,
61+
None => { ret = None; break }
62+
}
63+
}
64+
ret
65+
}
66+
}
67+
_ => None
68+
}
69+
}
70+
71+
/// Returns the first use of this value, if any
72+
pub fn get_first_use(self) -> Option<Use> {
73+
unsafe {
74+
match llvm::LLVMGetFirstUse(*self) {
75+
u if u.is_not_null() => Some(Use(u)),
76+
_ => None
77+
}
78+
}
79+
}
80+
81+
/// Tests if there are no uses of this value
82+
pub fn has_no_uses(self) -> bool {
83+
self.get_first_use().is_none()
84+
}
85+
86+
/// Returns the single user of this value
87+
/// If there are no users or multiple users, this returns None
88+
pub fn get_single_user(self) -> Option<Value> {
89+
let mut iter = self.user_iter();
90+
match (iter.next(), iter.next()) {
91+
(Some(first), None) => Some(first),
92+
_ => None
93+
}
94+
}
95+
96+
/// Returns an iterator for the users of this value
97+
pub fn user_iter(self) -> UserIterator {
98+
UserIterator {
99+
next: self.get_first_use()
100+
}
101+
}
102+
103+
/// Returns the requested operand of this instruction
104+
/// Returns None, if there's no operand at the given index
105+
pub fn get_operand(self, i: uint) -> Option<Value> {
106+
opt_val!(llvm::LLVMGetOperand(*self, i as c_uint))
107+
}
108+
109+
/// Returns the Store represent by this value, if any
110+
pub fn as_store_inst(self) -> Option<Value> {
111+
opt_val!(llvm::LLVMIsAStoreInst(*self))
112+
}
113+
114+
/// Tests if this value is a terminator instruction
115+
pub fn is_a_terminator_inst(self) -> bool {
116+
unsafe {
117+
llvm::LLVMIsATerminatorInst(*self).is_not_null()
118+
}
119+
}
120+
}
121+
122+
pub struct Use(UseRef);
123+
124+
/**
125+
* Wrapper for LLVM UseRef
126+
*/
127+
impl Use {
128+
pub fn get_user(self) -> Value {
129+
unsafe {
130+
Value(llvm::LLVMGetUser(*self))
131+
}
132+
}
133+
134+
pub fn get_next_use(self) -> Option<Use> {
135+
unsafe {
136+
match llvm::LLVMGetNextUse(*self) {
137+
u if u.is_not_null() => Some(Use(u)),
138+
_ => None
139+
}
140+
}
141+
}
142+
}
143+
144+
/// Iterator for the users of a value
145+
pub struct UserIterator {
146+
priv next: Option<Use>
147+
}
148+
149+
impl Iterator<Value> for UserIterator {
150+
fn next(&mut self) -> Option<Value> {
151+
let current = self.next;
152+
153+
self.next = do current.chain |u| { u.get_next_use() };
154+
155+
do current.map |u| { u.get_user() }
156+
}
157+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern "C"
12+
int test() {
13+
return 5;
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[no_mangle]
12+
fn test() -> int {
13+
5
14+
}

0 commit comments

Comments
 (0)