Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/origin/master' into cleanup-ite…
Browse files Browse the repository at this point in the history
…rators
  • Loading branch information
erickt committed Aug 10, 2013
2 parents 5b2c1c5 + 2ba36ec commit c8a93ef
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 17 deletions.
26 changes: 13 additions & 13 deletions src/libextra/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ impl WaitQueue {
}
count
}

fn wait_end(&self) -> WaitEnd {
let (wait_end, signal_end) = comm::oneshot();
self.tail.send_deferred(signal_end);
wait_end
}
}

// The building-block used to make semaphores, mutexes, and rwlocks.
Expand Down Expand Up @@ -100,12 +106,9 @@ impl<Q:Send> Sem<Q> {
do (**self).with |state| {
state.count -= 1;
if state.count < 0 {
// Create waiter nobe.
let (WaitEnd, SignalEnd) = comm::oneshot();
// Tell outer scope we need to block.
waiter_nobe = Some(WaitEnd);
// Enqueue ourself.
state.waiters.tail.send_deferred(SignalEnd);
// Create waiter nobe, enqueue ourself, and tell
// outer scope we need to block.
waiter_nobe = Some(state.waiters.wait_end());
}
}
// Uncomment if you wish to test for sem races. Not valgrind-friendly.
Expand Down Expand Up @@ -201,10 +204,7 @@ impl<'self> Condvar<'self> {
* wait() is equivalent to wait_on(0).
*/
pub fn wait_on(&self, condvar_id: uint) {
// Create waiter nobe.
let (WaitEnd, SignalEnd) = comm::oneshot();
let mut WaitEnd = Some(WaitEnd);
let mut SignalEnd = Some(SignalEnd);
let mut WaitEnd = None;
let mut out_of_bounds = None;
do task::unkillable {
// Release lock, 'atomically' enqueuing ourselves in so doing.
Expand All @@ -216,9 +216,9 @@ impl<'self> Condvar<'self> {
if state.count <= 0 {
state.waiters.signal();
}
// Enqueue ourself to be woken up by a signaller.
let SignalEnd = SignalEnd.take_unwrap();
state.blocked[condvar_id].tail.send_deferred(SignalEnd);
// Create waiter nobe, and enqueue ourself to
// be woken up by a signaller.
WaitEnd = Some(state.blocked[condvar_id].wait_end());
} else {
out_of_bounds = Some(state.blocked.len());
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/lib/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,8 @@ pub mod llvm {
/* Selected entries from the downcasts. */
#[fast_ffi]
pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef;
#[fast_ffi]
pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef;

/** Writes a module to the specified path. Returns 0 on success. */
#[fast_ffi]
Expand Down
28 changes: 24 additions & 4 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ use middle::trans::monomorphize;
use middle::trans::tvec;
use middle::trans::type_of;
use middle::trans::type_of::*;
use middle::trans::value::Value;
use middle::ty;
use util::common::indenter;
use util::ppaux::{Repr, ty_to_str};
Expand Down Expand Up @@ -1792,11 +1793,30 @@ pub fn finish_fn(fcx: @mut FunctionContext, last_bcx: @mut Block) {
// Builds the return block for a function.
pub fn build_return_block(fcx: &FunctionContext, ret_cx: @mut Block) {
// Return the value if this function immediate; otherwise, return void.
if fcx.llretptr.is_some() && fcx.has_immediate_return_value {
Ret(ret_cx, Load(ret_cx, fcx.llretptr.unwrap()))
} else {
RetVoid(ret_cx)
if fcx.llretptr.is_none() || !fcx.has_immediate_return_value {
return RetVoid(ret_cx);
}

let retptr = Value(fcx.llretptr.unwrap());
let retval = match retptr.get_dominating_store(ret_cx) {
// If there's only a single store to the ret slot, we can directly return
// the value that was stored and omit the store and the alloca
Some(s) => {
let retval = *s.get_operand(0).unwrap();
s.erase_from_parent();

if retptr.has_no_uses() {
retptr.erase_from_parent();
}

retval
}
// Otherwise, load the return value from the ret slot
None => Load(ret_cx, fcx.llretptr.unwrap())
};


Ret(ret_cx, retval);
}

pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, }
Expand Down
42 changes: 42 additions & 0 deletions src/librustc/middle/trans/basic_block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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 lib::llvm::{llvm, BasicBlockRef};
use middle::trans::value::{UserIterator, Value};
use std::iterator::{Filter, Map};

pub struct BasicBlock(BasicBlockRef);

pub type PredIterator<'self> = Map<'self, Value, BasicBlock, Filter<'self, Value, UserIterator>>;

/**
* Wrapper for LLVM BasicBlockRef
*/
impl BasicBlock {
pub fn as_value(self) -> Value {
unsafe {
Value(llvm::LLVMBasicBlockAsValue(*self))
}
}

pub fn pred_iter(self) -> PredIterator {
self.as_value().user_iter()
.filter(|user| user.is_a_terminator_inst())
.map(|user| user.get_parent().unwrap())
}

pub fn get_single_predecessor(self) -> Option<BasicBlock> {
let mut iter = self.pred_iter();
match (iter.next(), iter.next()) {
(Some(first), None) => Some(first),
_ => None
}
}
}
2 changes: 2 additions & 0 deletions src/librustc/middle/trans/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ pub mod machine;
pub mod adt;
pub mod asm;
pub mod type_;
pub mod value;
pub mod basic_block;
157 changes: 157 additions & 0 deletions src/librustc/middle/trans/value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// 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 lib::llvm::{llvm, UseRef, ValueRef};
use middle::trans::basic_block::BasicBlock;
use middle::trans::common::Block;
use std::libc::c_uint;

pub struct Value(ValueRef);

macro_rules! opt_val ( ($e:expr) => (
unsafe {
match $e {
p if p.is_not_null() => Some(Value(p)),
_ => None
}
}
))

/**
* Wrapper for LLVM ValueRef
*/
impl Value {
/// Returns the BasicBlock that contains this value
pub fn get_parent(self) -> Option<BasicBlock> {
unsafe {
match llvm::LLVMGetInstructionParent(*self) {
p if p.is_not_null() => Some(BasicBlock(p)),
_ => None
}
}
}

/// Removes this value from its containing BasicBlock
pub fn erase_from_parent(self) {
unsafe {
llvm::LLVMInstructionEraseFromParent(*self);
}
}

/// Returns the single dominating store to this value, if any
/// This only performs a search for a trivially dominating store. The store
/// must be the only user of this value, and there must not be any conditional
/// branches between the store and the given block.
pub fn get_dominating_store(self, bcx: @mut Block) -> Option<Value> {
match self.get_single_user().chain(|user| user.as_store_inst()) {
Some(store) => {
do store.get_parent().chain |store_bb| {
let mut bb = BasicBlock(bcx.llbb);
let mut ret = Some(store);
while *bb != *store_bb {
match bb.get_single_predecessor() {
Some(pred) => bb = pred,
None => { ret = None; break }
}
}
ret
}
}
_ => None
}
}

/// Returns the first use of this value, if any
pub fn get_first_use(self) -> Option<Use> {
unsafe {
match llvm::LLVMGetFirstUse(*self) {
u if u.is_not_null() => Some(Use(u)),
_ => None
}
}
}

/// Tests if there are no uses of this value
pub fn has_no_uses(self) -> bool {
self.get_first_use().is_none()
}

/// Returns the single user of this value
/// If there are no users or multiple users, this returns None
pub fn get_single_user(self) -> Option<Value> {
let mut iter = self.user_iter();
match (iter.next(), iter.next()) {
(Some(first), None) => Some(first),
_ => None
}
}

/// Returns an iterator for the users of this value
pub fn user_iter(self) -> UserIterator {
UserIterator {
next: self.get_first_use()
}
}

/// Returns the requested operand of this instruction
/// Returns None, if there's no operand at the given index
pub fn get_operand(self, i: uint) -> Option<Value> {
opt_val!(llvm::LLVMGetOperand(*self, i as c_uint))
}

/// Returns the Store represent by this value, if any
pub fn as_store_inst(self) -> Option<Value> {
opt_val!(llvm::LLVMIsAStoreInst(*self))
}

/// Tests if this value is a terminator instruction
pub fn is_a_terminator_inst(self) -> bool {
unsafe {
llvm::LLVMIsATerminatorInst(*self).is_not_null()
}
}
}

pub struct Use(UseRef);

/**
* Wrapper for LLVM UseRef
*/
impl Use {
pub fn get_user(self) -> Value {
unsafe {
Value(llvm::LLVMGetUser(*self))
}
}

pub fn get_next_use(self) -> Option<Use> {
unsafe {
match llvm::LLVMGetNextUse(*self) {
u if u.is_not_null() => Some(Use(u)),
_ => None
}
}
}
}

/// Iterator for the users of a value
pub struct UserIterator {
priv next: Option<Use>
}

impl Iterator<Value> for UserIterator {
fn next(&mut self) -> Option<Value> {
let current = self.next;

self.next = do current.chain |u| { u.get_next_use() };

do current.map |u| { u.get_user() }
}
}
14 changes: 14 additions & 0 deletions src/test/codegen/single-return-value.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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.

extern "C"
int test() {
return 5;
}
14 changes: 14 additions & 0 deletions src/test/codegen/single-return-value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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.

#[no_mangle]
fn test() -> int {
5
}

5 comments on commit c8a93ef

@bors
Copy link
Contributor

@bors bors commented on c8a93ef Aug 10, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from erickt
at erickt@c8a93ef

@bors
Copy link
Contributor

@bors bors commented on c8a93ef Aug 10, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging erickt/rust/cleanup-iterators = c8a93ef into auto

@bors
Copy link
Contributor

@bors bors commented on c8a93ef Aug 10, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

erickt/rust/cleanup-iterators = c8a93ef merged ok, testing candidate = 8b9e1ce

@bors
Copy link
Contributor

@bors bors commented on c8a93ef Aug 10, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 8b9e1ce

Please sign in to comment.