<commit_before>use crate::core::compiler::unit_graph::UnitGraph;
use crate::core::compiler::{BuildConfig, CompileKind, Unit};
use crate::core::profiles::Profiles;
use crate::core::PackageSet;
use crate::core::Workspace;
use crate::util::config::Config;
use crate::util::errors::CargoResult;
use crate::util::interning::InternedString;
use crate::util::Rustc;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;

mod target_info;
pub use self::target_info::{
    FileFlavor, FileType, RustDocFingerprint, RustcTargetData, TargetInfo,
};

/// The build context, containing all information about a build task.
///
/// It is intended that this is mostly static information. Stuff that mutates
/// during the build can be found in the parent `Context`. (I say mostly,
/// because this has internal caching, but nothing that should be observable
/// or require &mut.)
pub struct BuildContext<'a, 'cfg> {
    /// The workspace the build is for.
    pub ws: &'a Workspace<'cfg>,

    /// The cargo configuration.
    pub config: &'cfg Config,
    pub profiles: Profiles,
    pub build_config: &'a BuildConfig,

    /// Extra compiler args for either `rustc` or `rustdoc`.
    pub extra_compiler_args: HashMap<Unit, Vec<String>>,

    /// Package downloader.
    ///
    /// This holds ownership of the `Package` objects.
    pub packages: PackageSet<'cfg>,

    /// Information about rustc and the target platform.
    pub target_data: RustcTargetData<'cfg>,

    /// The root units of `unit_graph` (units requested on the command-line).
    pub roots: Vec<Unit>,

    /// The dependency graph of units to compile.
    pub unit_graph: UnitGraph,

    /// Reverse-dependencies of documented units, used by the rustdoc --scrape-examples flag.
    pub scrape_units: Vec<Unit>,

    /// The list of all kinds that are involved in this build
    pub all_kinds: HashSet<CompileKind>,
}

impl<'a, 'cfg> BuildContext<'a, 'cfg> {
    pub fn new(
        ws: &'a Workspace<'cfg>,
        packages: PackageSet<'cfg>,
        build_config: &'a BuildConfig,
        profiles: Profiles,
        extra_compiler_args: HashMap<Unit, Vec<String>>,
        target_data: RustcTargetData<'cfg>,
        roots: Vec<Unit>,
        unit_graph: UnitGraph,
        scrape_units: Vec<Unit>,
    ) -> CargoResult<BuildContext<'a, 'cfg>> {
        let all_kinds = unit_graph
            .keys()
            .map(|u| u.kind)
            .chain(build_config.requested_kinds.iter().copied())
            .chain(std::iter::once(CompileKind::Host))
            .collect();

        Ok(BuildContext {
            ws,
            config: ws.config(),
            packages,
            build_config,
            profiles,
            extra_compiler_args,
            target_data,
            roots,
            unit_graph,
            scrape_units,
            all_kinds,
        })
    }

    pub fn rustc(&self) -> &Rustc {
        &self.target_data.rustc
    }

    /// Gets the user-specified linker for a particular host or target.
    pub fn linker(&self, kind: CompileKind) -> Option<PathBuf> {
        self.target_data
            .target_config(kind)
            .linker
            .as_ref()
            .map(|l| l.val.clone().resolve_program(self.config))
    }

    /// Gets the host architecture triple.
    ///
    /// For example, x86_64-unknown-linux-gnu, would be
    /// - machine: x86_64,
    /// - hardware-platform: unknown,
    /// - operating system: linux-gnu.
    pub fn host_triple(&self) -> InternedString {
        self.target_data.rustc.host
    }

    /// Gets the number of jobs specified for this build.
    pub fn jobs(&self) -> u32 {
        self.build_config.jobs
    }

    pub fn rustflags_args(&self, unit: &Unit) -> &[String] {
        &self.target_data.info(unit.kind).rustflags
    }

    pub fn rustdocflags_args(&self, unit: &Unit) -> &[String] {
        &self.target_data.info(unit.kind).rustdocflags
    }

    pub fn extra_args_for(&self, unit: &Unit) -> Option<&Vec<String>> {
        self.extra_compiler_args.get(unit)
    }
}
<commit_msg>doc(build_context): module level doc<commit_after>//! [`BuildContext`] is a (mostly) static information about a build task.

use crate::core::compiler::unit_graph::UnitGraph;
use crate::core::compiler::{BuildConfig, CompileKind, Unit};
use crate::core::profiles::Profiles;
use crate::core::PackageSet;
use crate::core::Workspace;
use crate::util::config::Config;
use crate::util::errors::CargoResult;
use crate::util::interning::InternedString;
use crate::util::Rustc;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;

mod target_info;
pub use self::target_info::{
    FileFlavor, FileType, RustDocFingerprint, RustcTargetData, TargetInfo,
};

/// The build context, containing complete infomration needed for a build task
/// before it gets started.
///
/// It is intended that this is mostly static information. Stuff that mutates
/// during the build can be found in the parent [`Context`]. (I say mostly,
/// because this has internal caching, but nothing that should be observable
/// or require &mut.)
///
/// As a result, almost every field on `BuildContext` is public, including
///
/// * a resolved [`UnitGraph`] of your dependencies,
/// * a [`Profiles`] containing compiler flags presets,
/// * a [`RustcTargetData`] containing host and target platform information,
/// * and a [`PackageSet`] for further package downloads,
///
/// just to name a few. Learn more on each own documentation.
///
/// # How to use
///
/// To prepare a build task, you may not want to use [`BuildContext::new`] directly,
/// since it is often too lower-level.
/// Instead, [`ops::create_bcx`] is usually what you are looking for.
///
/// [`Context`]: crate::core::compiler::Context
/// [`ops::create_bcx`]: crate::ops::create_bcx
pub struct BuildContext<'a, 'cfg> {
    /// The workspace the build is for.
    pub ws: &'a Workspace<'cfg>,

    /// The cargo configuration.
    pub config: &'cfg Config,

    /// This contains a collection of compiler flags presets.
    pub profiles: Profiles,

    /// Configuration information for a rustc build.
    pub build_config: &'a BuildConfig,

    /// Extra compiler args for either `rustc` or `rustdoc`.
    pub extra_compiler_args: HashMap<Unit, Vec<String>>,

    /// Package downloader.
    ///
    /// This holds ownership of the `Package` objects.
    pub packages: PackageSet<'cfg>,

    /// Information about rustc and the target platform.
    pub target_data: RustcTargetData<'cfg>,

    /// The root units of `unit_graph` (units requested on the command-line).
    pub roots: Vec<Unit>,

    /// The dependency graph of units to compile.
    pub unit_graph: UnitGraph,

    /// Reverse-dependencies of documented units, used by the `rustdoc --scrape-examples` flag.
    pub scrape_units: Vec<Unit>,

    /// The list of all kinds that are involved in this build
    pub all_kinds: HashSet<CompileKind>,
}

impl<'a, 'cfg> BuildContext<'a, 'cfg> {
    pub fn new(
        ws: &'a Workspace<'cfg>,
        packages: PackageSet<'cfg>,
        build_config: &'a BuildConfig,
        profiles: Profiles,
        extra_compiler_args: HashMap<Unit, Vec<String>>,
        target_data: RustcTargetData<'cfg>,
        roots: Vec<Unit>,
        unit_graph: UnitGraph,
        scrape_units: Vec<Unit>,
    ) -> CargoResult<BuildContext<'a, 'cfg>> {
        let all_kinds = unit_graph
            .keys()
            .map(|u| u.kind)
            .chain(build_config.requested_kinds.iter().copied())
            .chain(std::iter::once(CompileKind::Host))
            .collect();

        Ok(BuildContext {
            ws,
            config: ws.config(),
            packages,
            build_config,
            profiles,
            extra_compiler_args,
            target_data,
            roots,
            unit_graph,
            scrape_units,
            all_kinds,
        })
    }

    /// Information of the `rustc` this build task will use.
    pub fn rustc(&self) -> &Rustc {
        &self.target_data.rustc
    }

    /// Gets the user-specified linker for a particular host or target.
    pub fn linker(&self, kind: CompileKind) -> Option<PathBuf> {
        self.target_data
            .target_config(kind)
            .linker
            .as_ref()
            .map(|l| l.val.clone().resolve_program(self.config))
    }

    /// Gets the host architecture triple.
    ///
    /// For example, x86_64-unknown-linux-gnu, would be
    /// - machine: x86_64,
    /// - hardware-platform: unknown,
    /// - operating system: linux-gnu.
    pub fn host_triple(&self) -> InternedString {
        self.target_data.rustc.host
    }

    /// Gets the number of jobs specified for this build.
    pub fn jobs(&self) -> u32 {
        self.build_config.jobs
    }

    /// Extra compiler flags to pass to `rustc` for a given unit.
    ///
    /// Although it depends on the caller, in the current Cargo implementation,
    /// these flags take precendence over those from [`BuildContext::extra_args_for`].
    ///
    /// As of now, these flags come from environment variables and configurations.
    /// See [`TargetInfo.rustflags`] for more on how Cargo collects them.
    ///
    /// [`TargetInfo.rustflags`]: TargetInfo::rustflags
    pub fn rustflags_args(&self, unit: &Unit) -> &[String] {
        &self.target_data.info(unit.kind).rustflags
    }

    /// Extra compiler flags to pass to `rustdoc` for a given unit.
    ///
    /// Although it depends on the caller, in the current Cargo implementation,
    /// these flags take precendence over those from [`BuildContext::extra_args_for`].
    ///
    /// As of now, these flags come from environment variables and configurations.
    /// See [`TargetInfo.rustdocflags`] for more on how Cargo collects them.
    ///
    /// [`TargetInfo.rustdocflags`]: TargetInfo::rustdocflags
    pub fn rustdocflags_args(&self, unit: &Unit) -> &[String] {
        &self.target_data.info(unit.kind).rustdocflags
    }

    /// Extra compiler args for either `rustc` or `rustdoc`.
    ///
    /// As of now, these flags come from the trailing args of either
    /// `cargo rustc` or `cargo rustdoc`.
    pub fn extra_args_for(&self, unit: &Unit) -> Option<&Vec<String>> {
        self.extra_compiler_args.get(unit)
    }
}
<|endoftext|>


<commit_before>//! Branch relaxation and offset computation.
//!
//! # EBB header offsets
//!
//! Before we can generate binary machine code for branch instructions, we need to know the final
//! offsets of all the EBB headers in the function. This information is encoded in the
//! `func.offsets` table.
//!
//! # Branch relaxation
//!
//! Branch relaxation is the process of ensuring that all branches in the function have enough
//! range to encode their destination. It is common to have multiple branch encodings in an ISA.
//! For example, x86 branches can have either an 8-bit or a 32-bit displacement.
//!
//! On RISC architectures, it can happen that conditional branches have a shorter range than
//! unconditional branches:
//!
//! ```clif
//!     brz v1, ebb17
//! ```
//!
//! can be transformed into:
//!
//! ```clif
//!     brnz v1, ebb23
//!     jump ebb17
//! ebb23:
//! ```

use crate::binemit::{CodeInfo, CodeOffset};
use crate::cursor::{Cursor, FuncCursor};
use crate::dominator_tree::DominatorTree;
use crate::flowgraph::ControlFlowGraph;
use crate::ir::{Ebb, Function, Inst, InstructionData, Opcode, Value, ValueList};
use crate::isa::{EncInfo, TargetIsa};
use crate::iterators::IteratorExtras;
use crate::regalloc::RegDiversions;
use crate::timing;
use crate::CodegenResult;
use log::debug;

/// Relax branches and compute the final layout of EBB headers in `func`.
///
/// Fill in the `func.offsets` table so the function is ready for binary emission.
pub fn relax_branches(
    func: &mut Function,
    cfg: &mut ControlFlowGraph,
    domtree: &mut DominatorTree,
    isa: &dyn TargetIsa,
) -> CodegenResult<CodeInfo> {
    let _tt = timing::relax_branches();

    let encinfo = isa.encoding_info();

    // Clear all offsets so we can recognize EBBs that haven't been visited yet.
    func.offsets.clear();
    func.offsets.resize(func.dfg.num_ebbs());

    // Start by removing redundant jumps.
    // FIXME: Temporarily disabled due to #916.
    /* fold_redundant_jumps(func, cfg, domtree); */

    // Convert jumps to fallthrough instructions where possible.
    fallthroughs(func);

    let mut offset = 0;
    let mut divert = RegDiversions::new();

    // First, compute initial offsets for every EBB.
    {
        let mut cur = FuncCursor::new(func);
        while let Some(ebb) = cur.next_ebb() {
            divert.clear();
            cur.func.offsets[ebb] = offset;
            while let Some(inst) = cur.next_inst() {
                divert.apply(&cur.func.dfg[inst]);
                let enc = cur.func.encodings[inst];
                offset += encinfo.byte_size(enc, inst, &divert, &cur.func);
            }
        }
    }

    // Then, run the relaxation algorithm until it converges.
    let mut go_again = true;
    while go_again {
        go_again = false;
        offset = 0;

        // Visit all instructions in layout order.
        let mut cur = FuncCursor::new(func);
        while let Some(ebb) = cur.next_ebb() {
            divert.clear();
            // Record the offset for `ebb` and make sure we iterate until offsets are stable.
            if cur.func.offsets[ebb] != offset {
                cur.func.offsets[ebb] = offset;
                go_again = true;
            }

            while let Some(inst) = cur.next_inst() {
                divert.apply(&cur.func.dfg[inst]);

                let enc = cur.func.encodings[inst];

                // See if this is a branch has a range and a destination, and if the target is in
                // range.
                if let Some(range) = encinfo.branch_range(enc) {
                    if let Some(dest) = cur.func.dfg[inst].branch_destination() {
                        let dest_offset = cur.func.offsets[dest];
                        if !range.contains(offset, dest_offset) {
                            offset +=
                                relax_branch(&mut cur, &divert, offset, dest_offset, &encinfo, isa);
                            continue;
                        }
                    }
                }

                offset += encinfo.byte_size(enc, inst, &divert, &cur.func);
            }
        }
    }

    let code_size = offset;
    let jumptables = offset;

    for (jt, jt_data) in func.jump_tables.iter() {
        func.jt_offsets[jt] = offset;
        // TODO: this should be computed based on the min size needed to hold
        //        the furthest branch.
        offset += jt_data.len() as u32 * 4;
    }

    let jumptables_size = offset - jumptables;
    let rodata = offset;

    // TODO: Once we have constant pools we'll do some processing here to update offset.

    let rodata_size = offset - rodata;

    Ok(CodeInfo {
        code_size,
        jumptables_size,
        rodata_size,
        total_size: offset,
    })
}

/// Folds an instruction if it is a redundant jump.
/// Returns whether folding was performed (which invalidates the CFG).
fn try_fold_redundant_jump(
    func: &mut Function,
    cfg: &mut ControlFlowGraph,
    ebb: Ebb,
    first_inst: Inst,
) -> bool {
    let first_dest = match func.dfg[first_inst].branch_destination() {
        Some(ebb) => ebb, // The instruction was a single-target branch.
        None => {
            return false; // The instruction was either multi-target or not a branch.
        }
    };

    // Look at the first instruction of the first branch's destination.
    // If it is an unconditional branch, maybe the second jump can be bypassed.
    let second_inst = func.layout.first_inst(first_dest).expect("Instructions");
    if func.dfg[second_inst].opcode() != Opcode::Jump {
        return false;
    }

    // Now we need to fix up first_inst's ebb parameters to match second_inst's,
    // without changing the branch-specific arguments.
    //
    // The intermediary block is allowed to reference any SSA value that dominates it,
    // but that SSA value may not necessarily also dominate the instruction that's
    // being patched.

    // Get the arguments and parameters passed by the first branch.
    let num_fixed = func.dfg[first_inst]
        .opcode()
        .constraints()
        .num_fixed_value_arguments();
    let (first_args, first_params) = func.dfg[first_inst]
        .arguments(&func.dfg.value_lists)
        .split_at(num_fixed);

    // Get the parameters passed by the second jump.
    let num_fixed = func.dfg[second_inst]
        .opcode()
        .constraints()
        .num_fixed_value_arguments();
    let (_, second_params) = func.dfg[second_inst]
        .arguments(&func.dfg.value_lists)
        .split_at(num_fixed);
    let mut second_params = second_params.to_vec(); // Clone for rewriting below.

    // For each parameter passed by the second jump, if any of those parameters
    // was a block parameter, rewrite it to refer to the value that the first jump
    // passed in its parameters. Otherwise, make sure it dominates first_inst.
    //
    // For example: if we `ebb0: jump ebb1(v1)` to `ebb1(v2): jump ebb2(v2)`,
    // we want to rewrite the original jump to `jump ebb2(v1)`.
    let ebb_params: &[Value] = func.dfg.ebb_params(first_dest);
    debug_assert!(ebb_params.len() == first_params.len());

    for value in second_params.iter_mut() {
        if let Some((n, _)) = ebb_params.iter().enumerate().find(|(_, &p)| p == *value) {
            // This value was the Nth parameter passed to the second_inst's ebb.
            // Rewrite it as the Nth parameter passed by first_inst.
            *value = first_params[n];
        }
    }

    // Build a value list of first_args (unchanged) followed by second_params (rewritten).
    let arguments_vec: std::vec::Vec<_> = first_args
        .iter()
        .chain(second_params.iter())
        .map(|x| *x)
        .collect();
    let value_list = ValueList::from_slice(&arguments_vec, &mut func.dfg.value_lists);

    func.dfg[first_inst].take_value_list(); // Drop the current list.
    func.dfg[first_inst].put_value_list(value_list); // Put the new list.

    // Bypass the second jump.
    // This can disconnect the Ebb containing `second_inst`, to be cleaned up later.
    let second_dest = func.dfg[second_inst].branch_destination().expect("Dest");
    func.change_branch_destination(first_inst, second_dest);
    cfg.recompute_ebb(func, ebb);

    // The previously-intermediary Ebb may now be unreachable. Update CFG.
    if cfg.pred_iter(first_dest).count() == 0 {
        // Remove all instructions from that ebb.
        while let Some(inst) = func.layout.first_inst(first_dest) {
            func.layout.remove_inst(inst);
        }

        // Remove the block...
        cfg.recompute_ebb(func, first_dest); // ...from predecessor lists.
        func.layout.remove_ebb(first_dest); // ...from the layout.
    }

    return true;
}

/// Redirects `jump` instructions that point to other `jump` instructions to the final destination.
/// This transformation may orphan some blocks.
fn fold_redundant_jumps(
    func: &mut Function,
    cfg: &mut ControlFlowGraph,
    domtree: &mut DominatorTree,
) {
    let mut folded = false;

    // Postorder iteration guarantees that a chain of jumps is visited from
    // the end of the chain to the start of the chain.
    for &ebb in domtree.cfg_postorder() {
        // Only proceed if the first terminator instruction is a single-target branch.
        let first_inst = func.layout.last_inst(ebb).expect("Ebb has no terminator");
        folded |= try_fold_redundant_jump(func, cfg, ebb, first_inst);

        // Also try the previous instruction.
        if let Some(prev_inst) = func.layout.prev_inst(first_inst) {
            folded |= try_fold_redundant_jump(func, cfg, ebb, prev_inst);
        }
    }

    // Folding jumps invalidates the dominator tree.
    if folded {
        domtree.compute(func, cfg);
    }
}

/// Convert `jump` instructions to `fallthrough` instructions where possible and verify that any
/// existing `fallthrough` instructions are correct.
fn fallthroughs(func: &mut Function) {
    for (ebb, succ) in func.layout.ebbs().adjacent_pairs() {
        let term = func.layout.last_inst(ebb).expect("EBB has no terminator.");
        if let InstructionData::Jump {
            ref mut opcode,
            destination,
            ..
        } = func.dfg[term]
        {
            match *opcode {
                Opcode::Fallthrough => {
                    // Somebody used a fall-through instruction before the branch relaxation pass.
                    // Make sure it is correct, i.e. the destination is the layout successor.
                    debug_assert_eq!(destination, succ, "Illegal fall-through in {}", ebb)
                }
                Opcode::Jump => {
                    // If this is a jump to the successor EBB, change it to a fall-through.
                    if destination == succ {
                        *opcode = Opcode::Fallthrough;
                        func.encodings[term] = Default::default();
                    }
                }
                _ => {}
            }
        }
    }
}

/// Relax the branch instruction at `cur` so it can cover the range `offset - dest_offset`.
///
/// Return the size of the replacement instructions up to and including the location where `cur` is
/// left.
fn relax_branch(
    cur: &mut FuncCursor,
    divert: &RegDiversions,
    offset: CodeOffset,
    dest_offset: CodeOffset,
    encinfo: &EncInfo,
    isa: &dyn TargetIsa,
) -> CodeOffset {
    let inst = cur.current_inst().unwrap();
    debug!(
        "Relaxing [{}] {} for {:#x}-{:#x} range",
        encinfo.display(cur.func.encodings[inst]),
        cur.func.dfg.display_inst(inst, isa),
        offset,
        dest_offset
    );

    // Pick the smallest encoding that can handle the branch range.
    let dfg = &cur.func.dfg;
    let ctrl_type = dfg.ctrl_typevar(inst);
    if let Some(enc) = isa
        .legal_encodings(cur.func, &dfg[inst], ctrl_type)
        .filter(|&enc| {
            let range = encinfo.branch_range(enc).expect("Branch with no range");
            if !range.contains(offset, dest_offset) {
                debug!("  trying [{}]: out of range", encinfo.display(enc));
                false
            } else if encinfo.operand_constraints(enc)
                != encinfo.operand_constraints(cur.func.encodings[inst])
            {
                // Conservatively give up if the encoding has different constraints
                // than the original, so that we don't risk picking a new encoding
                // which the existing operands don't satisfy. We can't check for
                // validity directly because we don't have a RegDiversions active so
                // we don't know which registers are actually in use.
                debug!("  trying [{}]: constraints differ", encinfo.display(enc));
                false
            } else {
                debug!("  trying [{}]: OK", encinfo.display(enc));
                true
            }
        })
        .min_by_key(|&enc| encinfo.byte_size(enc, inst, &divert, &cur.func))
    {
        debug_assert!(enc != cur.func.encodings[inst]);
        cur.func.encodings[inst] = enc;
        return encinfo.byte_size(enc, inst, &divert, &cur.func);
    }

    // Note: On some RISC ISAs, conditional branches have shorter range than unconditional
    // branches, so one way of extending the range of a conditional branch is to invert its
    // condition and make it branch over an unconditional jump which has the larger range.
    //
    // Splitting the EBB is problematic this late because there may be register diversions in
    // effect across the conditional branch, and they can't survive the control flow edge to a new
    // EBB. We have two options for handling that:
    //
    // 1. Set a flag on the new EBB that indicates it wants the preserve the register diversions of
    //    its layout predecessor, or
    // 2. Use an encoding macro for the branch-over-jump pattern so we don't need to split the EBB.
    //
    // It seems that 1. would allow us to share code among RISC ISAs that need this.
    //
    // We can't allow register diversions to survive from the layout predecessor because the layout
    // predecessor could contain kill points for some values that are live in this EBB, and
    // diversions are not automatically cancelled when the live range of a value ends.

    // This assumes solution 2. above:
    panic!("No branch in range for {:#x}-{:#x}", offset, dest_offset);
}
<commit_msg>Make fold_redundant_jumps() feature-gated on basic-blocks<commit_after>//! Branch relaxation and offset computation.
//!
//! # EBB header offsets
//!
//! Before we can generate binary machine code for branch instructions, we need to know the final
//! offsets of all the EBB headers in the function. This information is encoded in the
//! `func.offsets` table.
//!
//! # Branch relaxation
//!
//! Branch relaxation is the process of ensuring that all branches in the function have enough
//! range to encode their destination. It is common to have multiple branch encodings in an ISA.
//! For example, x86 branches can have either an 8-bit or a 32-bit displacement.
//!
//! On RISC architectures, it can happen that conditional branches have a shorter range than
//! unconditional branches:
//!
//! ```clif
//!     brz v1, ebb17
//! ```
//!
//! can be transformed into:
//!
//! ```clif
//!     brnz v1, ebb23
//!     jump ebb17
//! ebb23:
//! ```

use crate::binemit::{CodeInfo, CodeOffset};
use crate::cursor::{Cursor, FuncCursor};
use crate::dominator_tree::DominatorTree;
use crate::flowgraph::ControlFlowGraph;
use crate::ir::{Function, InstructionData, Opcode};
use crate::isa::{EncInfo, TargetIsa};
use crate::iterators::IteratorExtras;
use crate::regalloc::RegDiversions;
use crate::timing;
use crate::CodegenResult;
use log::debug;

#[cfg(feature = "basic-blocks")]
use crate::ir::{Ebb, Inst, Value, ValueList};

/// Relax branches and compute the final layout of EBB headers in `func`.
///
/// Fill in the `func.offsets` table so the function is ready for binary emission.
pub fn relax_branches(
    func: &mut Function,
    _cfg: &mut ControlFlowGraph,
    _domtree: &mut DominatorTree,
    isa: &dyn TargetIsa,
) -> CodegenResult<CodeInfo> {
    let _tt = timing::relax_branches();

    let encinfo = isa.encoding_info();

    // Clear all offsets so we can recognize EBBs that haven't been visited yet.
    func.offsets.clear();
    func.offsets.resize(func.dfg.num_ebbs());

    // Start by removing redundant jumps.
    #[cfg(feature = "basic-blocks")]
    fold_redundant_jumps(func, _cfg, _domtree);

    // Convert jumps to fallthrough instructions where possible.
    fallthroughs(func);

    let mut offset = 0;
    let mut divert = RegDiversions::new();

    // First, compute initial offsets for every EBB.
    {
        let mut cur = FuncCursor::new(func);
        while let Some(ebb) = cur.next_ebb() {
            divert.clear();
            cur.func.offsets[ebb] = offset;
            while let Some(inst) = cur.next_inst() {
                divert.apply(&cur.func.dfg[inst]);
                let enc = cur.func.encodings[inst];
                offset += encinfo.byte_size(enc, inst, &divert, &cur.func);
            }
        }
    }

    // Then, run the relaxation algorithm until it converges.
    let mut go_again = true;
    while go_again {
        go_again = false;
        offset = 0;

        // Visit all instructions in layout order.
        let mut cur = FuncCursor::new(func);
        while let Some(ebb) = cur.next_ebb() {
            divert.clear();
            // Record the offset for `ebb` and make sure we iterate until offsets are stable.
            if cur.func.offsets[ebb] != offset {
                cur.func.offsets[ebb] = offset;
                go_again = true;
            }

            while let Some(inst) = cur.next_inst() {
                divert.apply(&cur.func.dfg[inst]);

                let enc = cur.func.encodings[inst];

                // See if this is a branch has a range and a destination, and if the target is in
                // range.
                if let Some(range) = encinfo.branch_range(enc) {
                    if let Some(dest) = cur.func.dfg[inst].branch_destination() {
                        let dest_offset = cur.func.offsets[dest];
                        if !range.contains(offset, dest_offset) {
                            offset +=
                                relax_branch(&mut cur, &divert, offset, dest_offset, &encinfo, isa);
                            continue;
                        }
                    }
                }

                offset += encinfo.byte_size(enc, inst, &divert, &cur.func);
            }
        }
    }

    let code_size = offset;
    let jumptables = offset;

    for (jt, jt_data) in func.jump_tables.iter() {
        func.jt_offsets[jt] = offset;
        // TODO: this should be computed based on the min size needed to hold
        //        the furthest branch.
        offset += jt_data.len() as u32 * 4;
    }

    let jumptables_size = offset - jumptables;
    let rodata = offset;

    // TODO: Once we have constant pools we'll do some processing here to update offset.

    let rodata_size = offset - rodata;

    Ok(CodeInfo {
        code_size,
        jumptables_size,
        rodata_size,
        total_size: offset,
    })
}

/// Folds an instruction if it is a redundant jump.
/// Returns whether folding was performed (which invalidates the CFG).
#[cfg(feature = "basic-blocks")]
fn try_fold_redundant_jump(
    func: &mut Function,
    cfg: &mut ControlFlowGraph,
    ebb: Ebb,
    first_inst: Inst,
) -> bool {
    let first_dest = match func.dfg[first_inst].branch_destination() {
        Some(ebb) => ebb, // The instruction was a single-target branch.
        None => {
            return false; // The instruction was either multi-target or not a branch.
        }
    };

    // Look at the first instruction of the first branch's destination.
    // If it is an unconditional branch, maybe the second jump can be bypassed.
    let second_inst = func.layout.first_inst(first_dest).expect("Instructions");
    if func.dfg[second_inst].opcode() != Opcode::Jump {
        return false;
    }

    // Now we need to fix up first_inst's ebb parameters to match second_inst's,
    // without changing the branch-specific arguments.
    //
    // The intermediary block is allowed to reference any SSA value that dominates it,
    // but that SSA value may not necessarily also dominate the instruction that's
    // being patched.

    // Get the arguments and parameters passed by the first branch.
    let num_fixed = func.dfg[first_inst]
        .opcode()
        .constraints()
        .num_fixed_value_arguments();
    let (first_args, first_params) = func.dfg[first_inst]
        .arguments(&func.dfg.value_lists)
        .split_at(num_fixed);

    // Get the parameters passed by the second jump.
    let num_fixed = func.dfg[second_inst]
        .opcode()
        .constraints()
        .num_fixed_value_arguments();
    let (_, second_params) = func.dfg[second_inst]
        .arguments(&func.dfg.value_lists)
        .split_at(num_fixed);
    let mut second_params = second_params.to_vec(); // Clone for rewriting below.

    // For each parameter passed by the second jump, if any of those parameters
    // was a block parameter, rewrite it to refer to the value that the first jump
    // passed in its parameters. Otherwise, make sure it dominates first_inst.
    //
    // For example: if we `ebb0: jump ebb1(v1)` to `ebb1(v2): jump ebb2(v2)`,
    // we want to rewrite the original jump to `jump ebb2(v1)`.
    let ebb_params: &[Value] = func.dfg.ebb_params(first_dest);
    debug_assert!(ebb_params.len() == first_params.len());

    for value in second_params.iter_mut() {
        if let Some((n, _)) = ebb_params.iter().enumerate().find(|(_, &p)| p == *value) {
            // This value was the Nth parameter passed to the second_inst's ebb.
            // Rewrite it as the Nth parameter passed by first_inst.
            *value = first_params[n];
        }
    }

    // Build a value list of first_args (unchanged) followed by second_params (rewritten).
    let arguments_vec: std::vec::Vec<_> = first_args
        .iter()
        .chain(second_params.iter())
        .map(|x| *x)
        .collect();
    let value_list = ValueList::from_slice(&arguments_vec, &mut func.dfg.value_lists);

    func.dfg[first_inst].take_value_list(); // Drop the current list.
    func.dfg[first_inst].put_value_list(value_list); // Put the new list.

    // Bypass the second jump.
    // This can disconnect the Ebb containing `second_inst`, to be cleaned up later.
    let second_dest = func.dfg[second_inst].branch_destination().expect("Dest");
    func.change_branch_destination(first_inst, second_dest);
    cfg.recompute_ebb(func, ebb);

    // The previously-intermediary Ebb may now be unreachable. Update CFG.
    if cfg.pred_iter(first_dest).count() == 0 {
        // Remove all instructions from that ebb.
        while let Some(inst) = func.layout.first_inst(first_dest) {
            func.layout.remove_inst(inst);
        }

        // Remove the block...
        cfg.recompute_ebb(func, first_dest); // ...from predecessor lists.
        func.layout.remove_ebb(first_dest); // ...from the layout.
    }

    return true;
}

/// Redirects `jump` instructions that point to other `jump` instructions to the final destination.
/// This transformation may orphan some blocks.
#[cfg(feature = "basic-blocks")]
fn fold_redundant_jumps(
    func: &mut Function,
    cfg: &mut ControlFlowGraph,
    domtree: &mut DominatorTree,
) {
    let mut folded = false;

    // Postorder iteration guarantees that a chain of jumps is visited from
    // the end of the chain to the start of the chain.
    for &ebb in domtree.cfg_postorder() {
        // Only proceed if the first terminator instruction is a single-target branch.
        let first_inst = func.layout.last_inst(ebb).expect("Ebb has no terminator");
        folded |= try_fold_redundant_jump(func, cfg, ebb, first_inst);

        // Also try the previous instruction.
        if let Some(prev_inst) = func.layout.prev_inst(first_inst) {
            folded |= try_fold_redundant_jump(func, cfg, ebb, prev_inst);
        }
    }

    // Folding jumps invalidates the dominator tree.
    if folded {
        domtree.compute(func, cfg);
    }
}

/// Convert `jump` instructions to `fallthrough` instructions where possible and verify that any
/// existing `fallthrough` instructions are correct.
fn fallthroughs(func: &mut Function) {
    for (ebb, succ) in func.layout.ebbs().adjacent_pairs() {
        let term = func.layout.last_inst(ebb).expect("EBB has no terminator.");
        if let InstructionData::Jump {
            ref mut opcode,
            destination,
            ..
        } = func.dfg[term]
        {
            match *opcode {
                Opcode::Fallthrough => {
                    // Somebody used a fall-through instruction before the branch relaxation pass.
                    // Make sure it is correct, i.e. the destination is the layout successor.
                    debug_assert_eq!(destination, succ, "Illegal fall-through in {}", ebb)
                }
                Opcode::Jump => {
                    // If this is a jump to the successor EBB, change it to a fall-through.
                    if destination == succ {
                        *opcode = Opcode::Fallthrough;
                        func.encodings[term] = Default::default();
                    }
                }
                _ => {}
            }
        }
    }
}

/// Relax the branch instruction at `cur` so it can cover the range `offset - dest_offset`.
///
/// Return the size of the replacement instructions up to and including the location where `cur` is
/// left.
fn relax_branch(
    cur: &mut FuncCursor,
    divert: &RegDiversions,
    offset: CodeOffset,
    dest_offset: CodeOffset,
    encinfo: &EncInfo,
    isa: &dyn TargetIsa,
) -> CodeOffset {
    let inst = cur.current_inst().unwrap();
    debug!(
        "Relaxing [{}] {} for {:#x}-{:#x} range",
        encinfo.display(cur.func.encodings[inst]),
        cur.func.dfg.display_inst(inst, isa),
        offset,
        dest_offset
    );

    // Pick the smallest encoding that can handle the branch range.
    let dfg = &cur.func.dfg;
    let ctrl_type = dfg.ctrl_typevar(inst);
    if let Some(enc) = isa
        .legal_encodings(cur.func, &dfg[inst], ctrl_type)
        .filter(|&enc| {
            let range = encinfo.branch_range(enc).expect("Branch with no range");
            if !range.contains(offset, dest_offset) {
                debug!("  trying [{}]: out of range", encinfo.display(enc));
                false
            } else if encinfo.operand_constraints(enc)
                != encinfo.operand_constraints(cur.func.encodings[inst])
            {
                // Conservatively give up if the encoding has different constraints
                // than the original, so that we don't risk picking a new encoding
                // which the existing operands don't satisfy. We can't check for
                // validity directly because we don't have a RegDiversions active so
                // we don't know which registers are actually in use.
                debug!("  trying [{}]: constraints differ", encinfo.display(enc));
                false
            } else {
                debug!("  trying [{}]: OK", encinfo.display(enc));
                true
            }
        })
        .min_by_key(|&enc| encinfo.byte_size(enc, inst, &divert, &cur.func))
    {
        debug_assert!(enc != cur.func.encodings[inst]);
        cur.func.encodings[inst] = enc;
        return encinfo.byte_size(enc, inst, &divert, &cur.func);
    }

    // Note: On some RISC ISAs, conditional branches have shorter range than unconditional
    // branches, so one way of extending the range of a conditional branch is to invert its
    // condition and make it branch over an unconditional jump which has the larger range.
    //
    // Splitting the EBB is problematic this late because there may be register diversions in
    // effect across the conditional branch, and they can't survive the control flow edge to a new
    // EBB. We have two options for handling that:
    //
    // 1. Set a flag on the new EBB that indicates it wants the preserve the register diversions of
    //    its layout predecessor, or
    // 2. Use an encoding macro for the branch-over-jump pattern so we don't need to split the EBB.
    //
    // It seems that 1. would allow us to share code among RISC ISAs that need this.
    //
    // We can't allow register diversions to survive from the layout predecessor because the layout
    // predecessor could contain kill points for some values that are live in this EBB, and
    // diversions are not automatically cancelled when the live range of a value ends.

    // This assumes solution 2. above:
    panic!("No branch in range for {:#x}-{:#x}", offset, dest_offset);
}
<|endoftext|>


<commit_before>use value::Value;
use mem::{GcStrategy, TracedRef};
use string::Str;
use number::*;
use VM;

use std::hash::*;
use std::fmt;

/// Kinds of error objects a `LibFn` can return
pub enum LibFnError {
    Val(Value),
    String(String),
}

impl From<String> for LibFnError {
    fn from(s: String) -> Self {
        LibFnError::String(s)
    }
}

impl From<TracedRef<Str>> for LibFnError {
    fn from(s: TracedRef<Str>) -> Self {
        LibFnError::Val(Value::String(s))
    }
}

impl From<Value> for LibFnError {
    fn from(v: Value) -> Self {
        LibFnError::Val(v)
    }
}

#[derive(Copy)]
pub struct LibFn(pub for<'a, 'b> fn(&'a mut VM,
                                    arg_start: usize,
                                    arg_count: u8,
                                    &'b mut FnMut(Value))
                                    -> Result<(), LibFnError>);

// Need to implement all of this stuff manually for now (I hope rustc will do that automatically)

impl Clone for LibFn {
    fn clone(&self) -> Self {
        LibFn(self.0)
    }
}

impl Hash for LibFn {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_usize(self.0 as usize);
    }
}

impl fmt::Pointer for LibFn {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{:p}", &self.0)
    }
}

impl fmt::Debug for LibFn {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "LibFn:{:p}", &self.0)
    }
}

impl PartialEq for LibFn {
    fn eq(&self, rhs: &Self) -> bool {
        self.0 as usize == rhs.0 as usize
    }
}

impl Eq for LibFn {}

#[test]
fn size() {
    use std::mem::size_of;
    assert_eq!(size_of::<LibFn>(), size_of::<usize>());
}

//===============================================================================================
// What follows is an abomination. *It* allows defining library function in a type-safe way. *It*
// also preserves metadata about the functions: Parameters and return values, including their
// declared values, are stored along with the function. *It* is also completely macro-based, so
// inexplicable behaviour is to be expected.
//
// If you want to live a happy life, don't scroll past this. You haven't missed anything. If you
// want to suffer for eternity, please continue and take a look at *it*.
//===============================================================================================

// If *it* has finally consumed you, here are a few todos:
// * Match arguments without slice patterns
//   This is useful since slice patterns are unstable. See the example at the bottom for how this
//   could look without slice patterns (it's not pretty). This could even be made its own crate,
//   since it's not entirely useless. Let's hope LLVM optimizes this right...
// * Autoderef values
//   Currently, if a function matches an argument with `name: string`, the type of name is
//   TracedRef<Str>. Autoderef could use the VMs GC to get a `&Str` instead. Smart use of traits
//   makes this easier. If the autoderef'd value is returned, it must be converted back to a Value.

pub enum TyMarker {
    Number,
    String,
    Bool,
    Array,
    Table,
    Fn,
    Any,
    Varargs,
}

pub type LibFnTyInfo = &'static [(
    &'static [(&'static str, TyMarker)],
    &'static [(&'static str, TyMarker)]
)];

/// Trait for all types that can be used in the `return [...]` of lib functions.
pub trait ToValues {
    fn to_values<F, G: GcStrategy>(self, mut push: F, gc: &mut G) where F: FnMut(Value);
}

impl ToValues for Value {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        push(self)
    }
}

impl<'a> ToValues for &'a [Value] {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        for value in self {
            push(*value)
        }
    }
}

impl ToValues for Number {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        push(Value::Number(self))
    }
}

impl ToValues for LeaFloat {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        push(Value::Number(self.into()))
    }
}

impl ToValues for LeaInt {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        push(Value::Number(self.into()))
    }
}

impl<T: Into<Str>> ToValues for T {
    fn to_values<F, G: GcStrategy>(self, mut push: F, gc: &mut G) where F: FnMut(Value) {
        push(Value::String(gc.intern_str(self)))
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_ident_to_ty_marker {
    ( number ) => ( $crate::libfn::TyMarker::Number );
    ( string ) => ( $crate::libfn::TyMarker::String );
    ( bool ) => ( $crate::libfn::TyMarker::Bool );
    ( array ) => ( $crate::libfn::TyMarker::Array );
    ( table ) => ( $crate::libfn::TyMarker::Table );
    ( fn ) => ( $crate::libfn::TyMarker::Fn );
    ( * ) => ( $crate::libfn::TyMarker::Any );
    ( ... ) => ( $crate::libfn::TyMarker::Varargs );
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_to_pat {
    ( $p:pat ) => ( $p );
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_build_ty_pat {
    ( [$($p:tt)*] , $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* ,] $($rest)*) };
    ( [$($p:tt)*] $name:ident : number $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::Number($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : string $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::String($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : bool $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::Bool($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : array $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::Array($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : table $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::Table($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : * $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $name] $($rest)*) };
    ( [$($p:tt)*] $name:ident : ... $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $name ..] $($rest)*) };
    ( [$($p:tt)*] ) =>
        { lea_to_pat!([$($p)*]) };
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_to_block {
    ( $b:block ) => ($b);
}

// FIXME Doesn't handle nested return
#[macro_export]
#[doc(hidden)]
macro_rules! lea_process_body {
    ( [$push_ret:ident; $vm:ident] [ $($t:tt)* ] return [ $($e:expr),* ] $($rest:tt)* ) => {
        lea_process_body!([$push_ret; $vm] [
            $($t)*
            {
                $(
                    ($e).to_values(|val| $push_ret(val), &mut $vm.gc);
                )*
                return Ok(());
            }
        ] $($rest)*);
    };
    /*( [$push_ret:ident; $vm:ident] [ $($t:tt)* ] { $($c:tt)* } $($rest:tt)* ) => {
        lea_process_body!([$push_ret] [ $($t)* {
            process_body!([$push_ret] [] $($c)*)
        } ] $($rest)* );
    };*/
    ( [$push_ret:ident; $vm:ident] [ $($t:tt)* ] $next:tt $($rest:tt)*) => {
        lea_process_body!([$push_ret; $vm] [$($t)* $next] $($rest)*);
    };
    ( [$push_ret:ident; $vm:ident] [$($t:tt)*] ) => {
        lea_to_block!({ $($t)* })
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_libfn_single {
    (fn $name:ident ($vm:ident) {
        $(
            ( $( $pname:ident : $pty:tt ),* ) ->
            ( $( $rname:ident : $rty:tt ),* ) =>
            { $($body:tt)* }
        )+
    } ) => {
        mod $name {
            use $crate::{VM, Value};
            use $crate::libfn::LibFnError;

            // Might not be used if the function doesn't return anything
            #[allow(unused_imports)]
            use $crate::libfn::ToValues;
            #[allow(unused_imports)]
            use $crate::mem::GcStrategy;

            #[allow(unreachable_code)]  // Don't warn when our inserted return isn't reachable
            pub fn $name($vm: &mut VM,
                         arg_start: usize,
                         arg_count: u8,
                         _push_ret: &mut FnMut(Value))
                         -> Result<(), LibFnError> {
                // TODO Figure out a way of matching param types without slice patterns
                match &$vm.stack[arg_start..arg_start+arg_count as usize] {
                    $(
                        // The `if true` at the end disables "unreachable pattern" errors
                        lea_build_ty_pat!([] $( $pname : $pty ),*) if true => {
                            lea_process_body!([_push_ret; $vm] [] $($body)*);
                            return Ok(());
                        }
                    )+

                    _ => {
                        // FIXME This could be a better message
                        return Err(format!(
                            "invalid arguments for call to {}",
                            stringify!($name)
                        ).into());
                    }
                }
            }
        }

        #[allow(non_upper_case_globals)]
        pub static $name: $crate::libfn::LibFnTyInfo = &[
            $(
                (
                    &[ $( (stringify!($pname), lea_ident_to_ty_marker!($pty)) ),* ],
                    &[ $( (stringify!($rname), lea_ident_to_ty_marker!($rty)) ),* ]
                )
            ),+
        ];
    };
}

/// Declare a list of library functions callable from Lea code.
///
/// ```rust
/// #![feature(slice_patterns)] // Needed by the macro
/// # #[macro_use] extern crate lea_vm;
///
/// lea_libfn! {
///     fn tostring(vm) {
///         (val: string) -> (s: string) => {
///             return [Value::String(val)]
///         }
///         (val: number) -> (s: string) => {
///             return [format!("{}", val)]
///         }
///     }
/// }
///
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! lea_libfn {
    ( $( fn $name:ident ($vm:ident) { $($b:tt)* } )+ ) => {
        $( lea_libfn_single!(fn $name ($vm) { $($b)* } ); )+
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_setenv {
    ( $env:ident; $gc:ident; $key:ident; $val:expr ) => {
        assert_eq!($env.set(
            Value::String($gc.intern_str(stringify!($key))),
            $val
        ).unwrap(), None);
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_lib_inner {
    ( $env:ident; $gc:ident; $gcty:ident; $key:ident = fn $f:ident, $($rest:tt)* ) => {
        lea_setenv!($env; $gc; $key; $crate::Value::LibFn($crate::libfn::LibFn($f::$f)));
        lea_lib_inner!($env; $gc; $gcty; $($rest)*);
    };
    ( $env:ident; $gc:ident; $gcty:ident; $key:ident = str $v:expr, $($rest:tt)* ) => {
        lea_setenv!($env; $gc; $key; $crate::Value::String($gc.intern_str($v)));
        lea_lib_inner!($env; $gc; $gcty; $($rest)*);
    };
    ( $env:ident; $gc:ident; $gcty:ident; ) => {};
}

/// Generate a `pub fn init` which will populate a `Table`. This can be used to declare loadable
/// libraries.
///
/// ```rust
/// # #[macro_use] extern crate lea_vm;
/// lea_lib! {
///     some_string = str "I am a string!".to_owned(),
/// }
///
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! lea_lib {
    ( $($t:tt)* ) => {
        pub fn init<G: $crate::mem::GcStrategy>(env: &mut $crate::Table, gc: &mut G) {
            use $crate::Value;

            lea_lib_inner!(env; gc; G; $($t)*);
        }
    }
}

// Dummy stuff below!

/*
mod dummyfn {
    use super::vm::libfn::LibFnError;

    pub fn dummyfn(args: &[super::vm::value::Value], _push_err: &mut FnMut(super::vm::value::Value))
    -> Result<(), LibFnError> {
        use super::vm::value::Value;

        // This is how slice-pattern-less type matching could look:
        {
            let rest = args;
            if let Some(next) = rest.first() {
                let rest: &[Value] = &rest[1..];
                match *next {
                    super::vm::value::Value::Number(_a) => {
                        if let Some(next) = rest.first() {
                            let rest: &[Value] = &rest[1..];
                            match *next {
                                super::vm::value::Value::Bool(_b) => {
                                    let _c = rest;
                                    {
                                        // First arm body here
                                    }
                                    return Ok(())
                                }
                                _ => {}
                            }
                        }
                    }
                    _ => {}
                }
            }
        }

        // If we land here, the first arm failed to match

        return Ok(())
    }
}
*/
<commit_msg>Print the types of invalid arguments for libfns<commit_after>use value::Value;
use mem::{GcStrategy, TracedRef};
use string::Str;
use number::*;
use VM;

use std::hash::*;
use std::fmt;

/// Kinds of error objects a `LibFn` can return
pub enum LibFnError {
    Val(Value),
    String(String),
}

impl From<String> for LibFnError {
    fn from(s: String) -> Self {
        LibFnError::String(s)
    }
}

impl From<TracedRef<Str>> for LibFnError {
    fn from(s: TracedRef<Str>) -> Self {
        LibFnError::Val(Value::String(s))
    }
}

impl From<Value> for LibFnError {
    fn from(v: Value) -> Self {
        LibFnError::Val(v)
    }
}

#[derive(Copy)]
pub struct LibFn(pub for<'a, 'b> fn(&'a mut VM,
                                    arg_start: usize,
                                    arg_count: u8,
                                    &'b mut FnMut(Value))
                                    -> Result<(), LibFnError>);

// Need to implement all of this stuff manually for now (I hope rustc will do that automatically)

impl Clone for LibFn {
    fn clone(&self) -> Self {
        LibFn(self.0)
    }
}

impl Hash for LibFn {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_usize(self.0 as usize);
    }
}

impl fmt::Pointer for LibFn {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{:p}", &self.0)
    }
}

impl fmt::Debug for LibFn {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "LibFn:{:p}", &self.0)
    }
}

impl PartialEq for LibFn {
    fn eq(&self, rhs: &Self) -> bool {
        self.0 as usize == rhs.0 as usize
    }
}

impl Eq for LibFn {}

#[test]
fn size() {
    use std::mem::size_of;
    assert_eq!(size_of::<LibFn>(), size_of::<usize>());
}

//===============================================================================================
// What follows is an abomination. *It* allows defining library function in a type-safe way. *It*
// also preserves metadata about the functions: Parameters and return values, including their
// declared values, are stored along with the function. *It* is also completely macro-based, so
// inexplicable behaviour is to be expected.
//
// If you want to live a happy life, don't scroll past this. You haven't missed anything. If you
// want to suffer for eternity, please continue and take a look at *it*.
//===============================================================================================

// If *it* has finally consumed you, here are a few todos:
// * Match arguments without slice patterns
//   This is useful since slice patterns are unstable. See the example at the bottom for how this
//   could look without slice patterns (it's not pretty). This could even be made its own crate,
//   since it's not entirely useless. Let's hope LLVM optimizes this right...
// * Autoderef values
//   Currently, if a function matches an argument with `name: string`, the type of name is
//   TracedRef<Str>. Autoderef could use the VMs GC to get a `&Str` instead. Smart use of traits
//   makes this easier. If the autoderef'd value is returned, it must be converted back to a Value.

pub enum TyMarker {
    Number,
    String,
    Bool,
    Array,
    Table,
    Fn,
    Any,
    Varargs,
}

pub type LibFnTyInfo = &'static [(
    &'static [(&'static str, TyMarker)],
    &'static [(&'static str, TyMarker)]
)];

/// Trait for all types that can be used in the `return [...]` of lib functions.
pub trait ToValues {
    fn to_values<F, G: GcStrategy>(self, mut push: F, gc: &mut G) where F: FnMut(Value);
}

impl ToValues for Value {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        push(self)
    }
}

impl<'a> ToValues for &'a [Value] {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        for value in self {
            push(*value)
        }
    }
}

impl ToValues for Number {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        push(Value::Number(self))
    }
}

impl ToValues for LeaFloat {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        push(Value::Number(self.into()))
    }
}

impl ToValues for LeaInt {
    fn to_values<F, G: GcStrategy>(self, mut push: F, _: &mut G) where F: FnMut(Value) {
        push(Value::Number(self.into()))
    }
}

impl<T: Into<Str>> ToValues for T {
    fn to_values<F, G: GcStrategy>(self, mut push: F, gc: &mut G) where F: FnMut(Value) {
        push(Value::String(gc.intern_str(self)))
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_ident_to_ty_marker {
    ( number ) => ( $crate::libfn::TyMarker::Number );
    ( string ) => ( $crate::libfn::TyMarker::String );
    ( bool ) => ( $crate::libfn::TyMarker::Bool );
    ( array ) => ( $crate::libfn::TyMarker::Array );
    ( table ) => ( $crate::libfn::TyMarker::Table );
    ( fn ) => ( $crate::libfn::TyMarker::Fn );
    ( * ) => ( $crate::libfn::TyMarker::Any );
    ( ... ) => ( $crate::libfn::TyMarker::Varargs );
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_to_pat {
    ( $p:pat ) => ( $p );
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_build_ty_pat {
    ( [$($p:tt)*] , $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* ,] $($rest)*) };
    ( [$($p:tt)*] $name:ident : number $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::Number($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : string $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::String($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : bool $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::Bool($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : array $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::Array($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : table $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $crate::Value::Table($name)] $($rest)*) };
    ( [$($p:tt)*] $name:ident : * $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $name] $($rest)*) };
    ( [$($p:tt)*] $name:ident : ... $($rest:tt)* ) =>
        { lea_build_ty_pat!([$($p)* $name ..] $($rest)*) };
    ( [$($p:tt)*] ) =>
        { lea_to_pat!([$($p)*]) };
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_to_block {
    ( $b:block ) => ($b);
}

// FIXME Doesn't handle nested return
#[macro_export]
#[doc(hidden)]
macro_rules! lea_process_body {
    ( [$push_ret:ident; $vm:ident] [ $($t:tt)* ] return [ $($e:expr),* ] $($rest:tt)* ) => {
        lea_process_body!([$push_ret; $vm] [
            $($t)*
            {
                $(
                    ($e).to_values(|val| $push_ret(val), &mut $vm.gc);
                )*
                return Ok(());
            }
        ] $($rest)*);
    };
    /*( [$push_ret:ident; $vm:ident] [ $($t:tt)* ] { $($c:tt)* } $($rest:tt)* ) => {
        lea_process_body!([$push_ret] [ $($t)* {
            process_body!([$push_ret] [] $($c)*)
        } ] $($rest)* );
    };*/
    ( [$push_ret:ident; $vm:ident] [ $($t:tt)* ] $next:tt $($rest:tt)*) => {
        lea_process_body!([$push_ret; $vm] [$($t)* $next] $($rest)*);
    };
    ( [$push_ret:ident; $vm:ident] [$($t:tt)*] ) => {
        lea_to_block!({ $($t)* })
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_libfn_single {
    (fn $name:ident ($vm:ident) {
        $(
            ( $( $pname:ident : $pty:tt ),* ) ->
            ( $( $rname:ident : $rty:tt ),* ) =>
            { $($body:tt)* }
        )+
    } ) => {
        mod $name {
            use $crate::{VM, Value};
            use $crate::libfn::LibFnError;

            // Might not be used if the function doesn't return anything
            #[allow(unused_imports)]
            use $crate::libfn::ToValues;
            #[allow(unused_imports)]
            use $crate::mem::GcStrategy;

            #[allow(unreachable_code)]  // Don't warn when our inserted return isn't reachable
            pub fn $name($vm: &mut VM,
                         arg_start: usize,
                         arg_count: u8,
                         _push_ret: &mut FnMut(Value))
                         -> Result<(), LibFnError> {
                // TODO Figure out a way of matching param types without slice patterns
                match &$vm.stack[arg_start..arg_start+arg_count as usize] {
                    $(
                        // The `if true` at the end disables "unreachable pattern" errors
                        lea_build_ty_pat!([] $( $pname : $pty ),*) if true => {
                            lea_process_body!([_push_ret; $vm] [] $($body)*);
                            return Ok(());
                        }
                    )+

                    _ => {
                        // FIXME This could be a better message
                        return Err(format!(
                            "invalid arguments for call to {}: got {}",
                            stringify!($name),
                            $vm.stack[arg_start..arg_start+arg_count as usize]
                                .iter()
                                .fold(String::new(), |mut s, arg| {
                                    s.push_str(arg.get_type_name());
                                    s
                                })
                        ).into());
                    }
                }
            }
        }

        #[allow(non_upper_case_globals)]
        pub static $name: $crate::libfn::LibFnTyInfo = &[
            $(
                (
                    &[ $( (stringify!($pname), lea_ident_to_ty_marker!($pty)) ),* ],
                    &[ $( (stringify!($rname), lea_ident_to_ty_marker!($rty)) ),* ]
                )
            ),+
        ];
    };
}

/// Declare a list of library functions callable from Lea code.
///
/// ```rust
/// #![feature(slice_patterns)] // Needed by the macro
/// # #[macro_use] extern crate lea_vm;
///
/// lea_libfn! {
///     fn tostring(vm) {
///         (val: string) -> (s: string) => {
///             return [Value::String(val)]
///         }
///         (val: number) -> (s: string) => {
///             return [format!("{}", val)]
///         }
///     }
/// }
///
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! lea_libfn {
    ( $( fn $name:ident ($vm:ident) { $($b:tt)* } )+ ) => {
        $( lea_libfn_single!(fn $name ($vm) { $($b)* } ); )+
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_setenv {
    ( $env:ident; $gc:ident; $key:ident; $val:expr ) => {
        assert_eq!($env.set(
            Value::String($gc.intern_str(stringify!($key))),
            $val
        ).unwrap(), None);
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! lea_lib_inner {
    ( $env:ident; $gc:ident; $gcty:ident; $key:ident = fn $f:ident, $($rest:tt)* ) => {
        lea_setenv!($env; $gc; $key; $crate::Value::LibFn($crate::libfn::LibFn($f::$f)));
        lea_lib_inner!($env; $gc; $gcty; $($rest)*);
    };
    ( $env:ident; $gc:ident; $gcty:ident; $key:ident = str $v:expr, $($rest:tt)* ) => {
        lea_setenv!($env; $gc; $key; $crate::Value::String($gc.intern_str($v)));
        lea_lib_inner!($env; $gc; $gcty; $($rest)*);
    };
    ( $env:ident; $gc:ident; $gcty:ident; ) => {};
}

/// Generate a `pub fn init` which will populate a `Table`. This can be used to declare loadable
/// libraries.
///
/// ```rust
/// # #[macro_use] extern crate lea_vm;
/// lea_lib! {
///     some_string = str "I am a string!".to_owned(),
/// }
///
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! lea_lib {
    ( $($t:tt)* ) => {
        pub fn init<G: $crate::mem::GcStrategy>(env: &mut $crate::Table, gc: &mut G) {
            use $crate::Value;

            lea_lib_inner!(env; gc; G; $($t)*);
        }
    }
}

// Dummy stuff below!

/*
mod dummyfn {
    use super::vm::libfn::LibFnError;

    pub fn dummyfn(args: &[super::vm::value::Value], _push_err: &mut FnMut(super::vm::value::Value))
    -> Result<(), LibFnError> {
        use super::vm::value::Value;

        // This is how slice-pattern-less type matching could look:
        {
            let rest = args;
            if let Some(next) = rest.first() {
                let rest: &[Value] = &rest[1..];
                match *next {
                    super::vm::value::Value::Number(_a) => {
                        if let Some(next) = rest.first() {
                            let rest: &[Value] = &rest[1..];
                            match *next {
                                super::vm::value::Value::Bool(_b) => {
                                    let _c = rest;
                                    {
                                        // First arm body here
                                    }
                                    return Ok(())
                                }
                                _ => {}
                            }
                        }
                    }
                    _ => {}
                }
            }
        }

        // If we land here, the first arm failed to match

        return Ok(())
    }
}
*/
<|endoftext|>


<commit_before>// 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.

//! Operations on boolean values (`bool` type)
//!
//! A `to_bit` conversion function.

#![doc(primitive = "bool")]

use num::{Int, one, zero};

/////////////////////////////////////////////////////////////////////////////
// Freestanding functions
/////////////////////////////////////////////////////////////////////////////

/// Convert a `bool` to an integer.
///
/// # Examples
///
/// ```rust
/// use std::bool;
///
/// assert_eq!(bool::to_bit::<u8>(true), 1u8);
/// assert_eq!(bool::to_bit::<u8>(false), 0u8);
/// ```
#[inline]
pub fn to_bit<N: Int>(p: bool) -> N {
    if p { one() } else { zero() }
}

#[cfg(test)]
mod tests {
    use realstd::prelude::*;
    use super::to_bit;

    #[test]
    fn test_to_bit() {
        assert_eq!(to_bit::<u8>(true), 1u8);
        assert_eq!(to_bit::<u8>(false), 0u8);
    }

    #[test]
    fn test_eq() {
        assert_eq!(false.eq(&true), false);
        assert_eq!(false == false, true);
        assert_eq!(false != true, true);
        assert_eq!(false.ne(&false), false);
    }

    #[test]
    fn test_bitand() {
        assert_eq!(false.bitand(&false), false);
        assert_eq!(true.bitand(&false), false);
        assert_eq!(false.bitand(&true), false);
        assert_eq!(true.bitand(&true), true);

        assert_eq!(false & false, false);
        assert_eq!(true & false, false);
        assert_eq!(false & true, false);
        assert_eq!(true & true, true);
    }

    #[test]
    fn test_bitor() {
        assert_eq!(false.bitor(&false), false);
        assert_eq!(true.bitor(&false), true);
        assert_eq!(false.bitor(&true), true);
        assert_eq!(true.bitor(&true), true);

        assert_eq!(false | false, false);
        assert_eq!(true | false, true);
        assert_eq!(false | true, true);
        assert_eq!(true | true, true);
    }

    #[test]
    fn test_bitxor() {
        assert_eq!(false.bitxor(&false), false);
        assert_eq!(true.bitxor(&false), true);
        assert_eq!(false.bitxor(&true), true);
        assert_eq!(true.bitxor(&true), false);

        assert_eq!(false ^ false, false);
        assert_eq!(true ^ false, true);
        assert_eq!(false ^ true, true);
        assert_eq!(true ^ true, false);
    }

    #[test]
    fn test_not() {
        assert_eq!(!true, false);
        assert_eq!(!false, true);
    }

    #[test]
    fn test_to_str() {
        let s = false.to_str();
        assert_eq!(s.as_slice(), "false");
        let s = true.to_str();
        assert_eq!(s.as_slice(), "true");
    }

    #[test]
    fn test_ord() {
        assert!(true > false);
        assert!(!(false > true));

        assert!(false < true);
        assert!(!(true < false));

        assert!(false <= false);
        assert!(false >= false);
        assert!(true <= true);
        assert!(true >= true);

        assert!(false <= true);
        assert!(!(false >= true));
        assert!(true >= false);
        assert!(!(true <= false));
    }

    #[test]
    fn test_totalord() {
        assert!(true.cmp(&true) == Equal);
        assert!(false.cmp(&false) == Equal);
        assert!(true.cmp(&false) == Greater);
        assert!(false.cmp(&true) == Less);
    }
}
<commit_msg>core: Remove bool::to_bit<commit_after>// 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.

//! The boolean type

#![doc(primitive = "bool")]

#[cfg(test)]
mod tests {
    use realstd::prelude::*;
    use super::to_bit;

    #[test]
    fn test_to_bit() {
        assert_eq!(to_bit::<u8>(true), 1u8);
        assert_eq!(to_bit::<u8>(false), 0u8);
    }

    #[test]
    fn test_eq() {
        assert_eq!(false.eq(&true), false);
        assert_eq!(false == false, true);
        assert_eq!(false != true, true);
        assert_eq!(false.ne(&false), false);
    }

    #[test]
    fn test_bitand() {
        assert_eq!(false.bitand(&false), false);
        assert_eq!(true.bitand(&false), false);
        assert_eq!(false.bitand(&true), false);
        assert_eq!(true.bitand(&true), true);

        assert_eq!(false & false, false);
        assert_eq!(true & false, false);
        assert_eq!(false & true, false);
        assert_eq!(true & true, true);
    }

    #[test]
    fn test_bitor() {
        assert_eq!(false.bitor(&false), false);
        assert_eq!(true.bitor(&false), true);
        assert_eq!(false.bitor(&true), true);
        assert_eq!(true.bitor(&true), true);

        assert_eq!(false | false, false);
        assert_eq!(true | false, true);
        assert_eq!(false | true, true);
        assert_eq!(true | true, true);
    }

    #[test]
    fn test_bitxor() {
        assert_eq!(false.bitxor(&false), false);
        assert_eq!(true.bitxor(&false), true);
        assert_eq!(false.bitxor(&true), true);
        assert_eq!(true.bitxor(&true), false);

        assert_eq!(false ^ false, false);
        assert_eq!(true ^ false, true);
        assert_eq!(false ^ true, true);
        assert_eq!(true ^ true, false);
    }

    #[test]
    fn test_not() {
        assert_eq!(!true, false);
        assert_eq!(!false, true);
    }

    #[test]
    fn test_to_str() {
        let s = false.to_str();
        assert_eq!(s.as_slice(), "false");
        let s = true.to_str();
        assert_eq!(s.as_slice(), "true");
    }

    #[test]
    fn test_ord() {
        assert!(true > false);
        assert!(!(false > true));

        assert!(false < true);
        assert!(!(true < false));

        assert!(false <= false);
        assert!(false >= false);
        assert!(true <= true);
        assert!(true >= true);

        assert!(false <= true);
        assert!(!(false >= true));
        assert!(true >= false);
        assert!(!(true <= false));
    }

    #[test]
    fn test_totalord() {
        assert!(true.cmp(&true) == Equal);
        assert!(false.cmp(&false) == Equal);
        assert!(true.cmp(&false) == Greater);
        assert!(false.cmp(&true) == Less);
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

//! Boolean logic

use option::{None, Option, Some};
use from_str::FromStr;

#[cfg(notest)] use cmp;

/// Negation / inverse
pub fn not(v: bool) -> bool { !v }

/// Conjunction
pub fn and(a: bool, b: bool) -> bool { a && b }

/// Disjunction
pub fn or(a: bool, b: bool) -> bool { a || b }

/**
 * Exclusive or
 *
 * Identical to `or(and(a, not(b)), and(not(a), b))`
 */
pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }

/// Implication in the logic, i.e. from `a` follows `b`
pub fn implies(a: bool, b: bool) -> bool { !a || b }

/// true if truth values `a` and `b` are indistinguishable in the logic
pub fn eq(a: bool, b: bool) -> bool { a == b }

/// true if truth values `a` and `b` are distinguishable in the logic
pub fn ne(a: bool, b: bool) -> bool { a != b }

/// true if `v` represents truth in the logic
pub fn is_true(v: bool) -> bool { v }

/// true if `v` represents falsehood in the logic
pub fn is_false(v: bool) -> bool { !v }

/// Parse logic value from `s`
impl FromStr for bool {
    fn from_str(s: &str) -> Option<bool> {
        if s == "true" {
            Some(true)
        } else if s == "false" {
            Some(false)
        } else {
            None
        }
    }
}

/// Convert `v` into a string
pub fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } }

/**
 * Iterates over all truth values by passing them to `blk` in an unspecified
 * order
 */
pub fn all_values(blk: &fn(v: bool)) {
    blk(true);
    blk(false);
}

/// converts truth value to an 8 bit byte
pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }

#[cfg(notest)]
impl cmp::Eq for bool {
    fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
    fn ne(&self, other: &bool) -> bool { (*self) != (*other) }
}

#[test]
pub fn test_bool_from_str() {
    use from_str::FromStr;

    do all_values |v| {
        assert!(Some(v) == FromStr::from_str(to_str(v)))
    }
}

#[test]
pub fn test_bool_to_str() {
    assert!(to_str(false) == ~"false");
    assert!(to_str(true) == ~"true");
}

#[test]
pub fn test_bool_to_bit() {
    do all_values |v| {
        assert!(to_bit(v) == if is_true(v) { 1u8 } else { 0u8 });
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>bool: implement Ord and TotalOrd<commit_after>// Copyright 2012 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.

//! Boolean logic

#[cfg(notest)]
use cmp::{Eq, Ord, TotalOrd, Ordering};
use option::{None, Option, Some};
use from_str::FromStr;

/// Negation / inverse
pub fn not(v: bool) -> bool { !v }

/// Conjunction
pub fn and(a: bool, b: bool) -> bool { a && b }

/// Disjunction
pub fn or(a: bool, b: bool) -> bool { a || b }

/**
 * Exclusive or
 *
 * Identical to `or(and(a, not(b)), and(not(a), b))`
 */
pub fn xor(a: bool, b: bool) -> bool { (a && !b) || (!a && b) }

/// Implication in the logic, i.e. from `a` follows `b`
pub fn implies(a: bool, b: bool) -> bool { !a || b }

/// true if truth values `a` and `b` are indistinguishable in the logic
pub fn eq(a: bool, b: bool) -> bool { a == b }

/// true if truth values `a` and `b` are distinguishable in the logic
pub fn ne(a: bool, b: bool) -> bool { a != b }

/// true if `v` represents truth in the logic
pub fn is_true(v: bool) -> bool { v }

/// true if `v` represents falsehood in the logic
pub fn is_false(v: bool) -> bool { !v }

/// Parse logic value from `s`
impl FromStr for bool {
    fn from_str(s: &str) -> Option<bool> {
        if s == "true" {
            Some(true)
        } else if s == "false" {
            Some(false)
        } else {
            None
        }
    }
}

/// Convert `v` into a string
pub fn to_str(v: bool) -> ~str { if v { ~"true" } else { ~"false" } }

/**
 * Iterates over all truth values by passing them to `blk` in an unspecified
 * order
 */
pub fn all_values(blk: &fn(v: bool)) {
    blk(true);
    blk(false);
}

/// converts truth value to an 8 bit byte
#[inline(always)]
pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } }

#[cfg(notest)]
impl Ord for bool {
    #[inline(always)]
    fn lt(&self, other: &bool) -> bool { to_bit(*self) < to_bit(*other) }
    #[inline(always)]
    fn le(&self, other: &bool) -> bool { to_bit(*self) <= to_bit(*other) }
    #[inline(always)]
    fn gt(&self, other: &bool) -> bool { to_bit(*self) > to_bit(*other) }
    #[inline(always)]
    fn ge(&self, other: &bool) -> bool { to_bit(*self) >= to_bit(*other) }
}

#[cfg(notest)]
impl TotalOrd for bool {
    #[inline(always)]
    fn cmp(&self, other: &bool) -> Ordering { to_bit(*self).cmp(&to_bit(*other)) }
}

#[cfg(notest)]
impl Eq for bool {
    #[inline(always)]
    fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
    #[inline(always)]
    fn ne(&self, other: &bool) -> bool { (*self) != (*other) }
}

#[cfg(test)]
mod tests {
    use super::*;
    use prelude::*;

    #[test]
    fn test_bool_from_str() {
        use from_str::FromStr;

        do all_values |v| {
            assert!(Some(v) == FromStr::from_str(to_str(v)))
        }
    }

    #[test]
    fn test_bool_to_str() {
        assert!(to_str(false) == ~"false");
        assert!(to_str(true) == ~"true");
    }

    #[test]
    fn test_bool_to_bit() {
        do all_values |v| {
            assert!(to_bit(v) == if is_true(v) { 1u8 } else { 0u8 });
        }
    }

    #[test]
    fn test_bool_ord() {
        assert!(true > false);
        assert!(!(false > true));

        assert!(false < true);
        assert!(!(true < false));

        assert!(false <= false);
        assert!(false >= false);
        assert!(true <= true);
        assert!(true >= true);

        assert!(false <= true);
        assert!(!(false >= true));
        assert!(true >= false);
        assert!(!(true <= false));
    }

    #[test]
    fn test_bool_totalord() {
        assert_eq!(true.cmp(&true), Equal);
        assert_eq!(false.cmp(&false), Equal);
        assert_eq!(true.cmp(&false), Greater);
        assert_eq!(false.cmp(&true), Less);
    }
}
<|endoftext|>


<commit_before>// Top-level, visible-everywhere definitions.

// Export various ubiquitous types, constructors, methods.

import option::{some, none};
import option = option::option;
import path = path::path;
import str::extensions;
import vec::extensions;
import option::extensions;
import option_iter::extensions;
import ptr::extensions;
import rand::extensions;

export path, option, some, none, unreachable;
export extensions;

// Export the log levels as global constants. Higher levels mean
// more-verbosity. Error is the bottom level, default logging level is
// warn-and-below.

export error, warn, info, debug;

#[doc = "The error log level"]
const error : u32 = 0_u32;
#[doc = "The warning log level"]
const warn : u32 = 1_u32;
#[doc = "The info log level"]
const info : u32 = 2_u32;
#[doc = "The debug log level"]
const debug : u32 = 3_u32;

// A curious inner-module that's not exported that contains the binding
// 'core' so that macro-expanded references to core::error and such
// can be resolved within libcore.
mod core {
    const error : u32 = 0_u32;
    const warn : u32 = 1_u32;
    const info : u32 = 2_u32;
    const debug : u32 = 3_u32;
}

// Similar to above. Some magic to make core testable.
#[cfg(test)]
mod std {
    use std(vers = "0.2");
    import std::test;
}

#[doc = "
A standard function to use to indicate unreachable code. Because the
function is guaranteed to fail typestate will correctly identify
any code paths following the appearance of this function as unreachable.
"]
fn unreachable() -> ! {
    fail "Internal error: entered unreachable code";
}

<commit_msg>core: Export result extensions from the top level<commit_after>// Top-level, visible-everywhere definitions.

// Export various ubiquitous types, constructors, methods.

import option::{some, none};
import option = option::option;
import path = path::path;
import str::extensions;
import vec::extensions;
import option::extensions;
import option_iter::extensions;
import ptr::extensions;
import rand::extensions;
import result::extensions;

export path, option, some, none, unreachable;
export extensions;

// Export the log levels as global constants. Higher levels mean
// more-verbosity. Error is the bottom level, default logging level is
// warn-and-below.

export error, warn, info, debug;

#[doc = "The error log level"]
const error : u32 = 0_u32;
#[doc = "The warning log level"]
const warn : u32 = 1_u32;
#[doc = "The info log level"]
const info : u32 = 2_u32;
#[doc = "The debug log level"]
const debug : u32 = 3_u32;

// A curious inner-module that's not exported that contains the binding
// 'core' so that macro-expanded references to core::error and such
// can be resolved within libcore.
mod core {
    const error : u32 = 0_u32;
    const warn : u32 = 1_u32;
    const info : u32 = 2_u32;
    const debug : u32 = 3_u32;
}

// Similar to above. Some magic to make core testable.
#[cfg(test)]
mod std {
    use std(vers = "0.2");
    import std::test;
}

#[doc = "
A standard function to use to indicate unreachable code. Because the
function is guaranteed to fail typestate will correctly identify
any code paths following the appearance of this function as unreachable.
"]
fn unreachable() -> ! {
    fail "Internal error: entered unreachable code";
}

<|endoftext|>


<commit_before>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
///
/// The [`unreachable!()`] macro is the safe counterpart of this function, which
/// will panic instead when executed.
///
/// [`unreachable!()`]: ../macro.unreachable.html
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, std::u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
pub unsafe fn unreachable_unchecked() -> ! {
    intrinsics::unreachable()
}

/// Save power or switch hyperthreads in a busy-wait spin-loop.
///
/// This function is deliberately more primitive than
/// [`std::thread::yield_now`](../../std/thread/fn.yield_now.html) and
/// does not directly yield to the system's scheduler.
/// In some cases it might be useful to use a combination of both functions.
/// Careful benchmarking is advised.
///
/// On some platforms this function may not do anything at all.
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(
        all(
            any(target_arch = "x86", target_arch = "x86_64"),
            target_feature = "sse2"
        )
    )] {
        #[cfg(target_arch = "x86")] {
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")] {
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(
        any(
            target_arch = "aarch64",
            all(target_arch = "arm", target_feature = "v6")
        )
    )] {
        #[cfg(target_arch = "aarch64")] {
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")] {
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[unstable(feature = "test", issue = "27812")]
pub fn black_box<T>(dummy: T) -> T {
    #[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))] {
        // we need to "use" the argument in some way LLVM can't
        // introspect.
        unsafe { asm!("" : : "r"(&dummy)) }
        dummy
    }
    #[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))] {
        #[inline(never)] fn black_box_(x: T) -> T { x }
        black_box_(dummy)
    }
}
<commit_msg>black_box should inhibit optimizations on platforms without inline assembly<commit_after>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
///
/// The [`unreachable!()`] macro is the safe counterpart of this function, which
/// will panic instead when executed.
///
/// [`unreachable!()`]: ../macro.unreachable.html
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, std::u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
pub unsafe fn unreachable_unchecked() -> ! {
    intrinsics::unreachable()
}

/// Save power or switch hyperthreads in a busy-wait spin-loop.
///
/// This function is deliberately more primitive than
/// [`std::thread::yield_now`](../../std/thread/fn.yield_now.html) and
/// does not directly yield to the system's scheduler.
/// In some cases it might be useful to use a combination of both functions.
/// Careful benchmarking is advised.
///
/// On some platforms this function may not do anything at all.
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(
        all(
            any(target_arch = "x86", target_arch = "x86_64"),
            target_feature = "sse2"
        )
    )] {
        #[cfg(target_arch = "x86")] {
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")] {
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(
        any(
            target_arch = "aarch64",
            all(target_arch = "arm", target_feature = "v6")
        )
    )] {
        #[cfg(target_arch = "aarch64")] {
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")] {
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[unstable(feature = "test", issue = "27812")]
pub fn black_box<T>(dummy: T) -> T {
    #[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))] {
        // we need to "use" the argument in some way LLVM can't
        // introspect.
        unsafe { asm!("" : : "r"(&dummy)) }
        dummy
    }
    #[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))] {
        unsafe {
            let ret = crate::ptr::read_volatile(&dummy);
            crate::mem::forget(dummy);
            ret
        }
   }
}
<|endoftext|>