Drop 'basic-blocks' feature (#1363)
* All: Drop 'basic-blocks' feature This makes it so that 'basic-blocks' cannot be disabled and we can start assuming it everywhere. * Tests: Replace non-bb filetests with bb version * Tests: Adapt solver-fixedconflict filetests to use basic blocks
This commit is contained in:
@@ -46,11 +46,9 @@ indicatif = "0.13.0"
|
|||||||
walkdir = "2.2"
|
walkdir = "2.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["disas", "wasm", "cranelift-codegen/all-arch", "basic-blocks"]
|
default = ["disas", "wasm", "cranelift-codegen/all-arch"]
|
||||||
disas = ["capstone"]
|
disas = ["capstone"]
|
||||||
wasm = ["wat", "cranelift-wasm"]
|
wasm = ["wat", "cranelift-wasm"]
|
||||||
basic-blocks = ["cranelift-codegen/basic-blocks", "cranelift-frontend/basic-blocks",
|
|
||||||
"cranelift-wasm/basic-blocks", "cranelift-filetests/basic-blocks"]
|
|
||||||
|
|
||||||
# We want debug symbols on release binaries by default since it allows profiling
|
# We want debug symbols on release binaries by default since it allows profiling
|
||||||
# tools to give more accurate information. We can always strip them out later if
|
# tools to give more accurate information. We can always strip them out later if
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ byteorder = { version = "1.3.2", default-features = false }
|
|||||||
cranelift-codegen-meta = { path = "meta", version = "0.56.0" }
|
cranelift-codegen-meta = { path = "meta", version = "0.56.0" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std", "basic-blocks", "unwind"]
|
default = ["std", "unwind"]
|
||||||
|
|
||||||
# The "std" feature enables use of libstd. The "core" feature enables use
|
# The "std" feature enables use of libstd. The "core" feature enables use
|
||||||
# of some minimal std-like replacement libraries. At least one of these two
|
# of some minimal std-like replacement libraries. At least one of these two
|
||||||
@@ -69,9 +69,6 @@ all-arch = [
|
|||||||
# For dependent crates that want to serialize some parts of cranelift
|
# For dependent crates that want to serialize some parts of cranelift
|
||||||
enable-serde = ["serde"]
|
enable-serde = ["serde"]
|
||||||
|
|
||||||
# Temporary feature that enforces basic block semantics.
|
|
||||||
basic-blocks = []
|
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "experimental" }
|
maintenance = { status = "experimental" }
|
||||||
travis-ci = { repository = "bytecodealliance/cranelift" }
|
travis-ci = { repository = "bytecodealliance/cranelift" }
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use crate::binemit::{CodeInfo, CodeOffset};
|
|||||||
use crate::cursor::{Cursor, FuncCursor};
|
use crate::cursor::{Cursor, FuncCursor};
|
||||||
use crate::dominator_tree::DominatorTree;
|
use crate::dominator_tree::DominatorTree;
|
||||||
use crate::flowgraph::ControlFlowGraph;
|
use crate::flowgraph::ControlFlowGraph;
|
||||||
use crate::ir::{Function, InstructionData, Opcode};
|
use crate::ir::{Ebb, Function, Inst, InstructionData, Opcode, Value, ValueList};
|
||||||
use crate::isa::{EncInfo, TargetIsa};
|
use crate::isa::{EncInfo, TargetIsa};
|
||||||
use crate::iterators::IteratorExtras;
|
use crate::iterators::IteratorExtras;
|
||||||
use crate::regalloc::RegDiversions;
|
use crate::regalloc::RegDiversions;
|
||||||
@@ -40,9 +40,6 @@ use crate::CodegenResult;
|
|||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use log::debug;
|
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`.
|
/// 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.
|
/// Fill in the `func.offsets` table so the function is ready for binary emission.
|
||||||
@@ -61,7 +58,6 @@ pub fn relax_branches(
|
|||||||
func.offsets.resize(func.dfg.num_ebbs());
|
func.offsets.resize(func.dfg.num_ebbs());
|
||||||
|
|
||||||
// Start by removing redundant jumps.
|
// Start by removing redundant jumps.
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
fold_redundant_jumps(func, _cfg, _domtree);
|
fold_redundant_jumps(func, _cfg, _domtree);
|
||||||
|
|
||||||
// Convert jumps to fallthrough instructions where possible.
|
// Convert jumps to fallthrough instructions where possible.
|
||||||
@@ -154,7 +150,6 @@ pub fn relax_branches(
|
|||||||
|
|
||||||
/// Folds an instruction if it is a redundant jump.
|
/// Folds an instruction if it is a redundant jump.
|
||||||
/// Returns whether folding was performed (which invalidates the CFG).
|
/// Returns whether folding was performed (which invalidates the CFG).
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
fn try_fold_redundant_jump(
|
fn try_fold_redundant_jump(
|
||||||
func: &mut Function,
|
func: &mut Function,
|
||||||
cfg: &mut ControlFlowGraph,
|
cfg: &mut ControlFlowGraph,
|
||||||
@@ -260,7 +255,6 @@ fn try_fold_redundant_jump(
|
|||||||
|
|
||||||
/// Redirects `jump` instructions that point to other `jump` instructions to the final destination.
|
/// Redirects `jump` instructions that point to other `jump` instructions to the final destination.
|
||||||
/// This transformation may orphan some blocks.
|
/// This transformation may orphan some blocks.
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
fn fold_redundant_jumps(
|
fn fold_redundant_jumps(
|
||||||
func: &mut Function,
|
func: &mut Function,
|
||||||
cfg: &mut ControlFlowGraph,
|
cfg: &mut ControlFlowGraph,
|
||||||
|
|||||||
@@ -636,7 +636,6 @@ impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut FuncCursor<'f> {
|
|||||||
|
|
||||||
fn insert_built_inst(self, inst: ir::Inst, _: ir::Type) -> &'c mut ir::DataFlowGraph {
|
fn insert_built_inst(self, inst: ir::Inst, _: ir::Type) -> &'c mut ir::DataFlowGraph {
|
||||||
// TODO: Remove this assertion once #796 is fixed.
|
// TODO: Remove this assertion once #796 is fixed.
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
if let CursorPosition::At(_) = self.position() {
|
if let CursorPosition::At(_) = self.position() {
|
||||||
@@ -766,7 +765,6 @@ impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut EncCursor<'f> {
|
|||||||
ctrl_typevar: ir::Type,
|
ctrl_typevar: ir::Type,
|
||||||
) -> &'c mut ir::DataFlowGraph {
|
) -> &'c mut ir::DataFlowGraph {
|
||||||
// TODO: Remove this assertion once #796 is fixed.
|
// TODO: Remove this assertion once #796 is fixed.
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
if let CursorPosition::At(_) = self.position() {
|
if let CursorPosition::At(_) = self.position() {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use crate::ir;
|
|||||||
use crate::ir::{DataFlowGraph, ExternalName, Layout, Signature};
|
use crate::ir::{DataFlowGraph, ExternalName, Layout, Signature};
|
||||||
use crate::ir::{
|
use crate::ir::{
|
||||||
Ebb, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Heap, HeapData, Inst, JumpTable,
|
Ebb, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Heap, HeapData, Inst, JumpTable,
|
||||||
JumpTableData, SigRef, StackSlot, StackSlotData, Table, TableData,
|
JumpTableData, Opcode, SigRef, StackSlot, StackSlotData, Table, TableData,
|
||||||
};
|
};
|
||||||
use crate::ir::{EbbOffsets, FrameLayout, InstEncodings, SourceLocs, StackSlots, ValueLocations};
|
use crate::ir::{EbbOffsets, FrameLayout, InstEncodings, SourceLocs, StackSlots, ValueLocations};
|
||||||
use crate::ir::{JumpTableOffsets, JumpTables};
|
use crate::ir::{JumpTableOffsets, JumpTables};
|
||||||
@@ -19,9 +19,6 @@ use crate::value_label::ValueLabelsRanges;
|
|||||||
use crate::write::write_function;
|
use crate::write::write_function;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
use crate::ir::Opcode;
|
|
||||||
|
|
||||||
/// A function.
|
/// A function.
|
||||||
///
|
///
|
||||||
/// Functions can be cloned, but it is not a very fast operation.
|
/// Functions can be cloned, but it is not a very fast operation.
|
||||||
@@ -273,7 +270,6 @@ impl Function {
|
|||||||
/// Checks that the specified EBB can be encoded as a basic block.
|
/// Checks that the specified EBB can be encoded as a basic block.
|
||||||
///
|
///
|
||||||
/// On error, returns the first invalid instruction and an error message.
|
/// On error, returns the first invalid instruction and an error message.
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
pub fn is_ebb_basic(&self, ebb: Ebb) -> Result<(), (Inst, &'static str)> {
|
pub fn is_ebb_basic(&self, ebb: Ebb) -> Result<(), (Inst, &'static str)> {
|
||||||
let dfg = &self.dfg;
|
let dfg = &self.dfg;
|
||||||
let inst_iter = self.layout.ebb_insts(ebb);
|
let inst_iter = self.layout.ebb_insts(ebb);
|
||||||
|
|||||||
@@ -189,19 +189,18 @@ fn perform_repairs(pos: &mut FuncCursor, cfg: &ControlFlowGraph, mut repairs: Ve
|
|||||||
|
|
||||||
// Split the old argument, possibly causing more repairs to be scheduled.
|
// Split the old argument, possibly causing more repairs to be scheduled.
|
||||||
pos.goto_inst(inst);
|
pos.goto_inst(inst);
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
{
|
|
||||||
let inst_ebb = pos.func.layout.inst_ebb(inst).expect("inst in ebb");
|
|
||||||
|
|
||||||
// Insert split values prior to the terminal branch group.
|
let inst_ebb = pos.func.layout.inst_ebb(inst).expect("inst in ebb");
|
||||||
let canonical = pos
|
|
||||||
.func
|
// Insert split values prior to the terminal branch group.
|
||||||
.layout
|
let canonical = pos
|
||||||
.canonical_branch_inst(&pos.func.dfg, inst_ebb);
|
.func
|
||||||
if let Some(first_branch) = canonical {
|
.layout
|
||||||
pos.goto_inst(first_branch);
|
.canonical_branch_inst(&pos.func.dfg, inst_ebb);
|
||||||
}
|
if let Some(first_branch) = canonical {
|
||||||
|
pos.goto_inst(first_branch);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (lo, hi) = split_value(pos, old_arg, repair.concat, &mut repairs);
|
let (lo, hi) = split_value(pos, old_arg, repair.concat, &mut repairs);
|
||||||
|
|
||||||
// The `lo` part replaces the original argument.
|
// The `lo` part replaces the original argument.
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
//!
|
//!
|
||||||
//! One of the reason for splitting edges is to be able to insert `copy` and `regmove` instructions
|
//! One of the reason for splitting edges is to be able to insert `copy` and `regmove` instructions
|
||||||
//! between a conditional branch and the following terminator.
|
//! between a conditional branch and the following terminator.
|
||||||
#![cfg(feature = "basic-blocks")]
|
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::cursor::{Cursor, EncCursor};
|
use crate::cursor::{Cursor, EncCursor};
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ impl<'a> Context<'a> {
|
|||||||
// We are not able to insert any regmove for diversion or un-diversion after the first
|
// We are not able to insert any regmove for diversion or un-diversion after the first
|
||||||
// branch. Instead, we record the diversion to be restored at the entry of the next EBB,
|
// branch. Instead, we record the diversion to be restored at the entry of the next EBB,
|
||||||
// which should have a single predecessor.
|
// which should have a single predecessor.
|
||||||
if opcode.is_branch() && cfg!(feature = "basic-blocks") {
|
if opcode.is_branch() {
|
||||||
// The next instruction is necessarily an unconditional branch.
|
// The next instruction is necessarily an unconditional branch.
|
||||||
if let Some(branch) = self.cur.next_inst() {
|
if let Some(branch) = self.cur.next_inst() {
|
||||||
debug!(
|
debug!(
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use crate::dominator_tree::DominatorTree;
|
|||||||
use crate::flowgraph::ControlFlowGraph;
|
use crate::flowgraph::ControlFlowGraph;
|
||||||
use crate::ir::Function;
|
use crate::ir::Function;
|
||||||
use crate::isa::TargetIsa;
|
use crate::isa::TargetIsa;
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
use crate::regalloc::branch_splitting;
|
use crate::regalloc::branch_splitting;
|
||||||
use crate::regalloc::coalescing::Coalescing;
|
use crate::regalloc::coalescing::Coalescing;
|
||||||
use crate::regalloc::coloring::Coloring;
|
use crate::regalloc::coloring::Coloring;
|
||||||
@@ -96,10 +95,7 @@ impl Context {
|
|||||||
self.tracker.clear();
|
self.tracker.clear();
|
||||||
|
|
||||||
// Pass: Split branches, add space where to add copy & regmove instructions.
|
// Pass: Split branches, add space where to add copy & regmove instructions.
|
||||||
#[cfg(feature = "basic-blocks")]
|
branch_splitting::run(isa, func, cfg, domtree, &mut self.topo);
|
||||||
{
|
|
||||||
branch_splitting::run(isa, func, cfg, domtree, &mut self.topo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass: Liveness analysis.
|
// Pass: Liveness analysis.
|
||||||
self.liveness.compute(isa, func, cfg);
|
self.liveness.compute(isa, func, cfg);
|
||||||
|
|||||||
@@ -504,7 +504,6 @@ impl<'a> Verifier<'a> {
|
|||||||
|
|
||||||
/// Check that the given EBB can be encoded as a BB, by checking that only
|
/// Check that the given EBB can be encoded as a BB, by checking that only
|
||||||
/// branching instructions are ending the EBB.
|
/// branching instructions are ending the EBB.
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
fn encodable_as_bb(&self, ebb: Ebb, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
|
fn encodable_as_bb(&self, ebb: Ebb, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
|
||||||
match self.func.is_ebb_basic(ebb) {
|
match self.func.is_ebb_basic(ebb) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
@@ -1983,7 +1982,6 @@ impl<'a> Verifier<'a> {
|
|||||||
self.immediate_constraints(inst, errors)?;
|
self.immediate_constraints(inst, errors)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
self.encodable_as_bb(ebb, errors)?;
|
self.encodable_as_bb(ebb, errors)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,3 @@ memmap = "0.7.0"
|
|||||||
num_cpus = "1.8.0"
|
num_cpus = "1.8.0"
|
||||||
region = "2.1.2"
|
region = "2.1.2"
|
||||||
byteorder = { version = "1.3.2", default-features = false }
|
byteorder = { version = "1.3.2", default-features = false }
|
||||||
|
|
||||||
[features]
|
|
||||||
basic-blocks = []
|
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
test compile
|
|
||||||
set opt_level=speed_and_size
|
|
||||||
target x86_64
|
|
||||||
feature "basic-blocks"
|
|
||||||
; regex: V=v\d+
|
|
||||||
; regex: EBB=ebb\d+
|
|
||||||
|
|
||||||
function u0:0(i64) system_v {
|
|
||||||
ss0 = explicit_slot 1
|
|
||||||
jt0 = jump_table [ebb1]
|
|
||||||
|
|
||||||
ebb0(v0: i64):
|
|
||||||
v1 = stack_addr.i64 ss0
|
|
||||||
v2 = load.i8 v1
|
|
||||||
br_table v2, ebb2, jt0
|
|
||||||
; check: $(oob=$V) = ifcmp_imm $(idx=$V), 1
|
|
||||||
; ebb2 is replaced by ebb1 by fold_redundant_jump
|
|
||||||
; nextln: brif uge $oob, ebb1
|
|
||||||
; nextln: fallthrough $(inb=$EBB)
|
|
||||||
; check: $inb:
|
|
||||||
; nextln: $(final_idx=$V) = uextend.i64 $idx
|
|
||||||
; nextln: $(base=$V) = jump_table_base.i64 jt0
|
|
||||||
; nextln: $(rel_addr=$V) = jump_table_entry $final_idx, $base, 4, jt0
|
|
||||||
; nextln: $(addr=$V) = iadd $base, $rel_addr
|
|
||||||
; nextln: indirect_jump_table_br $addr, jt0
|
|
||||||
|
|
||||||
ebb2:
|
|
||||||
jump ebb1
|
|
||||||
|
|
||||||
ebb1:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
test compile
|
test compile
|
||||||
set opt_level=speed_and_size
|
set opt_level=speed_and_size
|
||||||
target x86_64
|
target x86_64
|
||||||
feature !"basic-blocks"
|
|
||||||
; regex: V=v\d+
|
; regex: V=v\d+
|
||||||
; regex: EBB=ebb\d+
|
; regex: EBB=ebb\d+
|
||||||
|
|
||||||
@@ -14,7 +13,8 @@ ebb0(v0: i64):
|
|||||||
v2 = load.i8 v1
|
v2 = load.i8 v1
|
||||||
br_table v2, ebb2, jt0
|
br_table v2, ebb2, jt0
|
||||||
; check: $(oob=$V) = ifcmp_imm $(idx=$V), 1
|
; check: $(oob=$V) = ifcmp_imm $(idx=$V), 1
|
||||||
; nextln: brif uge $oob, ebb2
|
; ebb2 is replaced by ebb1 by fold_redundant_jump
|
||||||
|
; nextln: brif uge $oob, ebb1
|
||||||
; nextln: fallthrough $(inb=$EBB)
|
; nextln: fallthrough $(inb=$EBB)
|
||||||
; check: $inb:
|
; check: $inb:
|
||||||
; nextln: $(final_idx=$V) = uextend.i64 $idx
|
; nextln: $(final_idx=$V) = uextend.i64 $idx
|
||||||
|
|||||||
@@ -1,158 +0,0 @@
|
|||||||
test regalloc
|
|
||||||
target riscv32
|
|
||||||
feature "basic-blocks"
|
|
||||||
|
|
||||||
; Test the coalescer.
|
|
||||||
; regex: V=v\d+
|
|
||||||
; regex: WS=\s+
|
|
||||||
; regex: LOC=%\w+
|
|
||||||
; regex: EBB=ebb\d+
|
|
||||||
|
|
||||||
; This function is already CSSA, so no copies should be inserted.
|
|
||||||
function %cssa(i32) -> i32 {
|
|
||||||
ebb0(v0: i32):
|
|
||||||
; not: copy
|
|
||||||
; v0 is used by the branch and passed as an arg - that's no conflict.
|
|
||||||
brnz v0, ebb1(v0)
|
|
||||||
jump ebb2
|
|
||||||
|
|
||||||
ebb2:
|
|
||||||
; v0 is live across the branch above. That's no conflict.
|
|
||||||
v1 = iadd_imm v0, 7
|
|
||||||
jump ebb1(v1)
|
|
||||||
|
|
||||||
ebb1(v10: i32):
|
|
||||||
v11 = iadd_imm v10, 7
|
|
||||||
return v11
|
|
||||||
}
|
|
||||||
|
|
||||||
function %trivial(i32) -> i32 {
|
|
||||||
ebb0(v0: i32):
|
|
||||||
; check: brnz v0, $(splitEdge=$EBB)
|
|
||||||
brnz v0, ebb1(v0)
|
|
||||||
jump ebb2
|
|
||||||
|
|
||||||
ebb2:
|
|
||||||
; not: copy
|
|
||||||
v1 = iadd_imm v0, 7
|
|
||||||
jump ebb1(v1)
|
|
||||||
|
|
||||||
; check: $splitEdge:
|
|
||||||
; nextln: $(cp1=$V) = copy.i32 v0
|
|
||||||
; nextln: jump ebb1($cp1)
|
|
||||||
|
|
||||||
ebb1(v10: i32):
|
|
||||||
; Use v0 in the destination EBB causes a conflict.
|
|
||||||
v11 = iadd v10, v0
|
|
||||||
return v11
|
|
||||||
}
|
|
||||||
|
|
||||||
; A value is used as an SSA argument twice in the same branch.
|
|
||||||
function %dualuse(i32) -> i32 {
|
|
||||||
ebb0(v0: i32):
|
|
||||||
; check: brnz v0, $(splitEdge=$EBB)
|
|
||||||
brnz v0, ebb1(v0, v0)
|
|
||||||
jump ebb2
|
|
||||||
|
|
||||||
ebb2:
|
|
||||||
v1 = iadd_imm v0, 7
|
|
||||||
v2 = iadd_imm v1, 56
|
|
||||||
jump ebb1(v1, v2)
|
|
||||||
|
|
||||||
; check: $splitEdge:
|
|
||||||
; check: $(cp1=$V) = copy.i32 v0
|
|
||||||
; nextln: jump ebb1($cp1, v0)
|
|
||||||
|
|
||||||
ebb1(v10: i32, v11: i32):
|
|
||||||
v12 = iadd v10, v11
|
|
||||||
return v12
|
|
||||||
}
|
|
||||||
|
|
||||||
; Interference away from the branch
|
|
||||||
; The interference can be broken with a copy at either branch.
|
|
||||||
function %interference(i32) -> i32 {
|
|
||||||
ebb0(v0: i32):
|
|
||||||
; not: copy
|
|
||||||
; check: brnz v0, $(splitEdge=$EBB)
|
|
||||||
; not: copy
|
|
||||||
brnz v0, ebb1(v0)
|
|
||||||
jump ebb2
|
|
||||||
|
|
||||||
ebb2:
|
|
||||||
v1 = iadd_imm v0, 7
|
|
||||||
; v1 and v0 interfere here:
|
|
||||||
v2 = iadd_imm v0, 8
|
|
||||||
; check: $(cp0=$V) = copy v1
|
|
||||||
; check: jump ebb1($cp0)
|
|
||||||
jump ebb1(v1)
|
|
||||||
|
|
||||||
; check: $splitEdge:
|
|
||||||
; not: copy
|
|
||||||
; nextln: jump ebb1(v0)
|
|
||||||
|
|
||||||
ebb1(v10: i32):
|
|
||||||
; not: copy
|
|
||||||
v11 = iadd_imm v10, 7
|
|
||||||
return v11
|
|
||||||
}
|
|
||||||
|
|
||||||
; A loop where one induction variable is used as a backedge argument.
|
|
||||||
function %fibonacci(i32) -> i32 {
|
|
||||||
ebb0(v0: i32):
|
|
||||||
v1 = iconst.i32 1
|
|
||||||
v2 = iconst.i32 2
|
|
||||||
jump ebb1(v1, v2)
|
|
||||||
|
|
||||||
; check: $(splitEdge=$EBB):
|
|
||||||
; check: $(nv11b=$V) = copy.i32 v11
|
|
||||||
; not: copy
|
|
||||||
; check: jump ebb1($nv11b, v12)
|
|
||||||
|
|
||||||
ebb1(v10: i32, v11: i32):
|
|
||||||
; v11 needs to be isolated because it interferes with v10.
|
|
||||||
; check: ebb1(v10: i32 [$LOC], $(nv11a=$V): i32 [$LOC])
|
|
||||||
; check: v11 = copy $nv11a
|
|
||||||
v12 = iadd v10, v11
|
|
||||||
v13 = icmp ult v12, v0
|
|
||||||
; check: brnz v13, $splitEdge
|
|
||||||
brnz v13, ebb1(v11, v12)
|
|
||||||
jump ebb2
|
|
||||||
|
|
||||||
ebb2:
|
|
||||||
return v12
|
|
||||||
}
|
|
||||||
|
|
||||||
; Function arguments passed on the stack aren't allowed to be part of a virtual
|
|
||||||
; register, at least for now. This is because the other values in the virtual
|
|
||||||
; register would need to be spilled to the incoming_arg stack slot which we treat
|
|
||||||
; as belonging to the caller.
|
|
||||||
function %stackarg(i32, i32, i32, i32, i32, i32, i32, i32, i32) -> i32 {
|
|
||||||
; check: ss0 = incoming_arg 4
|
|
||||||
; not: incoming_arg
|
|
||||||
ebb0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32, v7: i32, v8: i32):
|
|
||||||
; check: fill v8
|
|
||||||
; not: v8
|
|
||||||
jump ebb1(v8)
|
|
||||||
|
|
||||||
ebb1(v10: i32):
|
|
||||||
v11 = iadd_imm v10, 1
|
|
||||||
return v11
|
|
||||||
}
|
|
||||||
|
|
||||||
function %gvn_unremovable_phi(i32) system_v {
|
|
||||||
ebb0(v0: i32):
|
|
||||||
v2 = iconst.i32 0
|
|
||||||
jump ebb2(v2, v0)
|
|
||||||
|
|
||||||
ebb2(v3: i32, v4: i32):
|
|
||||||
brnz v3, ebb2(v3, v4)
|
|
||||||
jump ebb3
|
|
||||||
|
|
||||||
ebb3:
|
|
||||||
v5 = iconst.i32 1
|
|
||||||
brnz v3, ebb2(v2, v5)
|
|
||||||
jump ebb4
|
|
||||||
|
|
||||||
ebb4:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
test regalloc
|
test regalloc
|
||||||
target riscv32
|
target riscv32
|
||||||
feature !"basic-blocks"
|
|
||||||
|
|
||||||
; Test the coalescer.
|
; Test the coalescer.
|
||||||
; regex: V=v\d+
|
; regex: V=v\d+
|
||||||
; regex: WS=\s+
|
; regex: WS=\s+
|
||||||
; regex: LOC=%\w+
|
; regex: LOC=%\w+
|
||||||
|
; regex: EBB=ebb\d+
|
||||||
|
|
||||||
; This function is already CSSA, so no copies should be inserted.
|
; This function is already CSSA, so no copies should be inserted.
|
||||||
function %cssa(i32) -> i32 {
|
function %cssa(i32) -> i32 {
|
||||||
@@ -27,8 +27,7 @@ ebb1(v10: i32):
|
|||||||
|
|
||||||
function %trivial(i32) -> i32 {
|
function %trivial(i32) -> i32 {
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
; check: $(cp1=$V) = copy v0
|
; check: brnz v0, $(splitEdge=$EBB)
|
||||||
; nextln: brnz v0, ebb1($cp1)
|
|
||||||
brnz v0, ebb1(v0)
|
brnz v0, ebb1(v0)
|
||||||
jump ebb2
|
jump ebb2
|
||||||
|
|
||||||
@@ -37,6 +36,10 @@ ebb2:
|
|||||||
v1 = iadd_imm v0, 7
|
v1 = iadd_imm v0, 7
|
||||||
jump ebb1(v1)
|
jump ebb1(v1)
|
||||||
|
|
||||||
|
; check: $splitEdge:
|
||||||
|
; nextln: $(cp1=$V) = copy.i32 v0
|
||||||
|
; nextln: jump ebb1($cp1)
|
||||||
|
|
||||||
ebb1(v10: i32):
|
ebb1(v10: i32):
|
||||||
; Use v0 in the destination EBB causes a conflict.
|
; Use v0 in the destination EBB causes a conflict.
|
||||||
v11 = iadd v10, v0
|
v11 = iadd v10, v0
|
||||||
@@ -46,8 +49,7 @@ ebb1(v10: i32):
|
|||||||
; A value is used as an SSA argument twice in the same branch.
|
; A value is used as an SSA argument twice in the same branch.
|
||||||
function %dualuse(i32) -> i32 {
|
function %dualuse(i32) -> i32 {
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
; check: $(cp1=$V) = copy v0
|
; check: brnz v0, $(splitEdge=$EBB)
|
||||||
; nextln: brnz v0, ebb1($cp1, v0)
|
|
||||||
brnz v0, ebb1(v0, v0)
|
brnz v0, ebb1(v0, v0)
|
||||||
jump ebb2
|
jump ebb2
|
||||||
|
|
||||||
@@ -56,6 +58,10 @@ ebb2:
|
|||||||
v2 = iadd_imm v1, 56
|
v2 = iadd_imm v1, 56
|
||||||
jump ebb1(v1, v2)
|
jump ebb1(v1, v2)
|
||||||
|
|
||||||
|
; check: $splitEdge:
|
||||||
|
; check: $(cp1=$V) = copy.i32 v0
|
||||||
|
; nextln: jump ebb1($cp1, v0)
|
||||||
|
|
||||||
ebb1(v10: i32, v11: i32):
|
ebb1(v10: i32, v11: i32):
|
||||||
v12 = iadd v10, v11
|
v12 = iadd v10, v11
|
||||||
return v12
|
return v12
|
||||||
@@ -65,9 +71,9 @@ ebb1(v10: i32, v11: i32):
|
|||||||
; The interference can be broken with a copy at either branch.
|
; The interference can be broken with a copy at either branch.
|
||||||
function %interference(i32) -> i32 {
|
function %interference(i32) -> i32 {
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
; check: $(cp0=$V) = copy v0
|
; not: copy
|
||||||
; not: copy
|
; check: brnz v0, $(splitEdge=$EBB)
|
||||||
; check: brnz v0, ebb1($cp0)
|
; not: copy
|
||||||
brnz v0, ebb1(v0)
|
brnz v0, ebb1(v0)
|
||||||
jump ebb2
|
jump ebb2
|
||||||
|
|
||||||
@@ -75,10 +81,14 @@ ebb2:
|
|||||||
v1 = iadd_imm v0, 7
|
v1 = iadd_imm v0, 7
|
||||||
; v1 and v0 interfere here:
|
; v1 and v0 interfere here:
|
||||||
v2 = iadd_imm v0, 8
|
v2 = iadd_imm v0, 8
|
||||||
; not: copy
|
; check: $(cp0=$V) = copy v1
|
||||||
; check: jump ebb1(v1)
|
; check: jump ebb1($cp0)
|
||||||
jump ebb1(v1)
|
jump ebb1(v1)
|
||||||
|
|
||||||
|
; check: $splitEdge:
|
||||||
|
; not: copy
|
||||||
|
; nextln: jump ebb1(v0)
|
||||||
|
|
||||||
ebb1(v10: i32):
|
ebb1(v10: i32):
|
||||||
; not: copy
|
; not: copy
|
||||||
v11 = iadd_imm v10, 7
|
v11 = iadd_imm v10, 7
|
||||||
@@ -92,15 +102,18 @@ ebb0(v0: i32):
|
|||||||
v2 = iconst.i32 2
|
v2 = iconst.i32 2
|
||||||
jump ebb1(v1, v2)
|
jump ebb1(v1, v2)
|
||||||
|
|
||||||
|
; check: $(splitEdge=$EBB):
|
||||||
|
; check: $(nv11b=$V) = copy.i32 v11
|
||||||
|
; not: copy
|
||||||
|
; check: jump ebb1($nv11b, v12)
|
||||||
|
|
||||||
ebb1(v10: i32, v11: i32):
|
ebb1(v10: i32, v11: i32):
|
||||||
; v11 needs to be isolated because it interferes with v10.
|
; v11 needs to be isolated because it interferes with v10.
|
||||||
; check: ebb1(v10: i32 [$LOC], $(nv11a=$V): i32 [$LOC])
|
; check: ebb1(v10: i32 [$LOC], $(nv11a=$V): i32 [$LOC])
|
||||||
; check: v11 = copy $nv11a
|
; check: v11 = copy $nv11a
|
||||||
v12 = iadd v10, v11
|
v12 = iadd v10, v11
|
||||||
v13 = icmp ult v12, v0
|
v13 = icmp ult v12, v0
|
||||||
; check: $(nv11b=$V) = copy v11
|
; check: brnz v13, $splitEdge
|
||||||
; not: copy
|
|
||||||
; check: brnz v13, ebb1($nv11b, v12)
|
|
||||||
brnz v13, ebb1(v11, v12)
|
brnz v13, ebb1(v11, v12)
|
||||||
jump ebb2
|
jump ebb2
|
||||||
|
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
test regalloc
|
|
||||||
target x86_64 haswell
|
|
||||||
feature "basic-blocks"
|
|
||||||
|
|
||||||
; regex: V=v\d+
|
|
||||||
; regex: EBB=ebb\d+
|
|
||||||
|
|
||||||
; Filed as https://github.com/bytecodealliance/cranelift/issues/208
|
|
||||||
;
|
|
||||||
; The verifier complains about a branch argument that is not in the same virtual register as the
|
|
||||||
; corresponding EBB argument.
|
|
||||||
;
|
|
||||||
; The problem was the reload pass rewriting EBB arguments on "brnz v9, ebb3(v9)"
|
|
||||||
|
|
||||||
function %pr208(i64 vmctx [%rdi]) system_v {
|
|
||||||
gv1 = vmctx
|
|
||||||
gv0 = iadd_imm.i64 gv1, -8
|
|
||||||
heap0 = static gv0, min 0, bound 0x5000, offset_guard 0x0040_0000
|
|
||||||
sig0 = (i64 vmctx [%rdi]) -> i32 [%rax] system_v
|
|
||||||
sig1 = (i64 vmctx [%rdi], i32 [%rsi]) system_v
|
|
||||||
fn0 = u0:1 sig0
|
|
||||||
fn1 = u0:3 sig1
|
|
||||||
|
|
||||||
ebb0(v0: i64):
|
|
||||||
v1 = iconst.i32 0
|
|
||||||
v2 = call fn0(v0)
|
|
||||||
v20 = iconst.i32 0x4ffe
|
|
||||||
v16 = icmp uge v2, v20
|
|
||||||
brz v16, ebb5
|
|
||||||
jump ebb9
|
|
||||||
|
|
||||||
ebb9:
|
|
||||||
trap heap_oob
|
|
||||||
|
|
||||||
ebb5:
|
|
||||||
v17 = uextend.i64 v2
|
|
||||||
v18 = iadd_imm.i64 v0, -8
|
|
||||||
v19 = load.i64 v18
|
|
||||||
v3 = iadd v19, v17
|
|
||||||
v4 = load.i32 v3
|
|
||||||
v21 = iconst.i32 0
|
|
||||||
v5 = icmp eq v4, v21
|
|
||||||
v6 = bint.i32 v5
|
|
||||||
brnz v6, ebb2
|
|
||||||
jump ebb3(v4)
|
|
||||||
|
|
||||||
; check: ebb5:
|
|
||||||
; check: jump ebb3(v4)
|
|
||||||
; check: $(splitEdge=$EBB):
|
|
||||||
; nextln: jump ebb3(v9)
|
|
||||||
|
|
||||||
ebb3(v7: i32):
|
|
||||||
call fn1(v0, v7)
|
|
||||||
v26 = iconst.i32 0x4ffe
|
|
||||||
v22 = icmp uge v7, v26
|
|
||||||
brz v22, ebb6
|
|
||||||
jump ebb10
|
|
||||||
|
|
||||||
ebb10:
|
|
||||||
trap heap_oob
|
|
||||||
|
|
||||||
ebb6:
|
|
||||||
v23 = uextend.i64 v7
|
|
||||||
v24 = iadd_imm.i64 v0, -8
|
|
||||||
v25 = load.i64 v24
|
|
||||||
v8 = iadd v25, v23
|
|
||||||
v9 = load.i32 v8+56
|
|
||||||
; check: v9 = spill
|
|
||||||
; check: brnz $V, $splitEdge
|
|
||||||
brnz v9, ebb3(v9)
|
|
||||||
jump ebb4
|
|
||||||
|
|
||||||
ebb4:
|
|
||||||
jump ebb2
|
|
||||||
|
|
||||||
ebb2:
|
|
||||||
v10 = iconst.i32 0
|
|
||||||
v31 = iconst.i32 0x4ffe
|
|
||||||
v27 = icmp uge v10, v31
|
|
||||||
brz v27, ebb7
|
|
||||||
jump ebb11
|
|
||||||
|
|
||||||
ebb11:
|
|
||||||
trap heap_oob
|
|
||||||
|
|
||||||
ebb7:
|
|
||||||
v28 = uextend.i64 v10
|
|
||||||
v29 = iadd_imm.i64 v0, -8
|
|
||||||
v30 = load.i64 v29
|
|
||||||
v11 = iadd v30, v28
|
|
||||||
v12 = load.i32 v11+12
|
|
||||||
call fn1(v0, v12)
|
|
||||||
v13 = iconst.i32 0
|
|
||||||
v36 = iconst.i32 0x4ffe
|
|
||||||
v32 = icmp uge v13, v36
|
|
||||||
brz v32, ebb8
|
|
||||||
jump ebb12
|
|
||||||
|
|
||||||
ebb12:
|
|
||||||
trap heap_oob
|
|
||||||
|
|
||||||
ebb8:
|
|
||||||
v33 = uextend.i64 v13
|
|
||||||
v34 = iadd_imm.i64 v0, -8
|
|
||||||
v35 = load.i64 v34
|
|
||||||
v14 = iadd v35, v33
|
|
||||||
v15 = load.i32 v14+12
|
|
||||||
call fn1(v0, v15)
|
|
||||||
jump ebb1
|
|
||||||
|
|
||||||
ebb1:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
test regalloc
|
test regalloc
|
||||||
target x86_64 haswell
|
target x86_64 haswell
|
||||||
feature !"basic-blocks"
|
|
||||||
|
|
||||||
; regex: V=v\d+
|
; regex: V=v\d+
|
||||||
|
; regex: EBB=ebb\d+
|
||||||
|
|
||||||
; Filed as https://github.com/bytecodealliance/cranelift/issues/208
|
; Filed as https://github.com/bytecodealliance/cranelift/issues/208
|
||||||
;
|
;
|
||||||
@@ -43,6 +43,11 @@ ebb5:
|
|||||||
brnz v6, ebb2
|
brnz v6, ebb2
|
||||||
jump ebb3(v4)
|
jump ebb3(v4)
|
||||||
|
|
||||||
|
; check: ebb5:
|
||||||
|
; check: jump ebb3(v4)
|
||||||
|
; check: $(splitEdge=$EBB):
|
||||||
|
; nextln: jump ebb3(v9)
|
||||||
|
|
||||||
ebb3(v7: i32):
|
ebb3(v7: i32):
|
||||||
call fn1(v0, v7)
|
call fn1(v0, v7)
|
||||||
v26 = iconst.i32 0x4ffe
|
v26 = iconst.i32 0x4ffe
|
||||||
@@ -60,7 +65,7 @@ ebb6:
|
|||||||
v8 = iadd v25, v23
|
v8 = iadd v25, v23
|
||||||
v9 = load.i32 v8+56
|
v9 = load.i32 v8+56
|
||||||
; check: v9 = spill
|
; check: v9 = spill
|
||||||
; check: brnz $V, ebb3(v9)
|
; check: brnz $V, $splitEdge
|
||||||
brnz v9, ebb3(v9)
|
brnz v9, ebb3(v9)
|
||||||
jump ebb4
|
jump ebb4
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ test compile
|
|||||||
set opt_level=speed
|
set opt_level=speed
|
||||||
set enable_pinned_reg=true
|
set enable_pinned_reg=true
|
||||||
target x86_64 haswell
|
target x86_64 haswell
|
||||||
feature !"basic-blocks"
|
|
||||||
|
|
||||||
function u0:0(i32, i32, i32, i64 vmctx) -> i64 uext system_v {
|
function u0:0(i32, i32, i32, i64 vmctx) -> i64 uext system_v {
|
||||||
ebb0(v0: i32, v1: i32, v2: i32, v3: i64):
|
ebb0(v0: i32, v1: i32, v2: i32, v3: i64):
|
||||||
@@ -11,8 +10,8 @@ ebb0(v0: i32, v1: i32, v2: i32, v3: i64):
|
|||||||
v16 = iconst.i32 -8
|
v16 = iconst.i32 -8
|
||||||
v17 = popcnt v16
|
v17 = popcnt v16
|
||||||
v192 = ifcmp_imm v17, -1
|
v192 = ifcmp_imm v17, -1
|
||||||
brif eq v192, ebb12
|
trapif ne v192, user0
|
||||||
trap user0
|
jump ebb12
|
||||||
|
|
||||||
ebb12:
|
ebb12:
|
||||||
v122 = iconst.i32 0
|
v122 = iconst.i32 0
|
||||||
@@ -23,8 +22,8 @@ ebb12:
|
|||||||
v204 = iconst.i32 0
|
v204 = iconst.i32 0
|
||||||
v31 -> v204
|
v31 -> v204
|
||||||
v210 = ifcmp_imm v31, -1
|
v210 = ifcmp_imm v31, -1
|
||||||
brif eq v210, ebb18
|
trapif ne v210, user0
|
||||||
trap user0
|
jump ebb18
|
||||||
|
|
||||||
ebb18:
|
ebb18:
|
||||||
v215 = iconst.i32 0
|
v215 = iconst.i32 0
|
||||||
@@ -33,8 +32,8 @@ ebb18:
|
|||||||
ebb19(v32: i32):
|
ebb19(v32: i32):
|
||||||
v35 = iconst.i32 0
|
v35 = iconst.i32 0
|
||||||
v218 = ifcmp_imm v35, -1
|
v218 = ifcmp_imm v35, -1
|
||||||
brif eq v218, ebb21
|
trapif ne v218, user0
|
||||||
trap user0
|
jump ebb21
|
||||||
|
|
||||||
ebb21:
|
ebb21:
|
||||||
v223 = iconst.i32 0
|
v223 = iconst.i32 0
|
||||||
@@ -44,8 +43,8 @@ ebb22(v36: i32):
|
|||||||
v136 = iconst.i32 0
|
v136 = iconst.i32 0
|
||||||
v40 -> v136
|
v40 -> v136
|
||||||
v227 = ifcmp_imm v136, -1
|
v227 = ifcmp_imm v136, -1
|
||||||
brif eq v227, ebb24
|
trapif ne v227, user0
|
||||||
trap user0
|
jump ebb24
|
||||||
|
|
||||||
ebb24:
|
ebb24:
|
||||||
v232 = iconst.i32 0
|
v232 = iconst.i32 0
|
||||||
@@ -55,8 +54,8 @@ ebb25(v41: i32):
|
|||||||
v142 = iconst.i32 0
|
v142 = iconst.i32 0
|
||||||
v45 -> v142
|
v45 -> v142
|
||||||
v236 = ifcmp_imm v142, -1
|
v236 = ifcmp_imm v142, -1
|
||||||
brif eq v236, ebb27
|
trapif ne v236, user0
|
||||||
trap user0
|
jump ebb27
|
||||||
|
|
||||||
ebb27:
|
ebb27:
|
||||||
v241 = iconst.i32 0
|
v241 = iconst.i32 0
|
||||||
@@ -65,8 +64,8 @@ ebb27:
|
|||||||
ebb28(v46: i32):
|
ebb28(v46: i32):
|
||||||
v49 = iconst.i32 0
|
v49 = iconst.i32 0
|
||||||
v244 = ifcmp_imm v49, -1
|
v244 = ifcmp_imm v49, -1
|
||||||
brif eq v244, ebb30
|
trapif ne v244, user0
|
||||||
trap user0
|
jump ebb30
|
||||||
|
|
||||||
ebb30:
|
ebb30:
|
||||||
v254 = iconst.i32 0
|
v254 = iconst.i32 0
|
||||||
@@ -92,9 +91,9 @@ ebb35:
|
|||||||
v60 -> v271
|
v60 -> v271
|
||||||
v61 = f32const 0.0
|
v61 = f32const 0.0
|
||||||
v280 = iconst.i32 0
|
v280 = iconst.i32 0
|
||||||
v281 = fcmp uno v61, v61
|
v281 = ffcmp v61, v61
|
||||||
brnz v281, ebb41(v280)
|
trapff ord v281, user0
|
||||||
trap user0
|
jump ebb41(v280)
|
||||||
|
|
||||||
ebb41(v62: i32):
|
ebb41(v62: i32):
|
||||||
v157 = iconst.i32 0
|
v157 = iconst.i32 0
|
||||||
@@ -103,8 +102,8 @@ ebb41(v62: i32):
|
|||||||
v160 = iadd v158, v159
|
v160 = iadd v158, v159
|
||||||
v75 -> v160
|
v75 -> v160
|
||||||
v308 = ifcmp_imm v160, -1
|
v308 = ifcmp_imm v160, -1
|
||||||
brif eq v308, ebb52
|
trapif ne v308, user0
|
||||||
trap user0
|
jump ebb52
|
||||||
|
|
||||||
ebb52:
|
ebb52:
|
||||||
v87 = iconst.i32 -23
|
v87 = iconst.i32 -23
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ test compile
|
|||||||
set opt_level=speed
|
set opt_level=speed
|
||||||
set enable_pinned_reg=true
|
set enable_pinned_reg=true
|
||||||
target x86_64 haswell
|
target x86_64 haswell
|
||||||
feature !"basic-blocks"
|
|
||||||
|
|
||||||
;; Test for the issue #1123; https://github.com/bytecodealliance/cranelift/issues/1123
|
;; Test for the issue #1123; https://github.com/bytecodealliance/cranelift/issues/1123
|
||||||
|
|
||||||
@@ -24,26 +23,26 @@ ebb0(v0: i32, v1: i32, v2: i32, v3: i64):
|
|||||||
v39 -> v533
|
v39 -> v533
|
||||||
v53 = iconst.i32 0
|
v53 = iconst.i32 0
|
||||||
v547 = ifcmp_imm v53, -1
|
v547 = ifcmp_imm v53, -1
|
||||||
brif eq v547, ebb30
|
trapif ne v547, user0
|
||||||
trap user0
|
jump ebb30
|
||||||
|
|
||||||
ebb30:
|
ebb30:
|
||||||
v75 = iconst.i32 0
|
v75 = iconst.i32 0
|
||||||
v581 = ifcmp_imm v75, -1
|
v581 = ifcmp_imm v75, -1
|
||||||
brif eq v581, ebb42
|
trapif ne v581, user0
|
||||||
trap user0
|
jump ebb42
|
||||||
|
|
||||||
ebb42:
|
ebb42:
|
||||||
v136 = iconst.i32 0
|
v136 = iconst.i32 0
|
||||||
v691 = ifcmp_imm v136, -1
|
v691 = ifcmp_imm v136, -1
|
||||||
brif eq v691, ebb81
|
trapif ne v691, user0
|
||||||
trap user0
|
jump ebb81
|
||||||
|
|
||||||
ebb81:
|
ebb81:
|
||||||
v158 = iconst.i32 0
|
v158 = iconst.i32 0
|
||||||
v725 = ifcmp_imm v158, -1
|
v725 = ifcmp_imm v158, -1
|
||||||
brif eq v725, ebb93
|
trapif ne v725, user0
|
||||||
trap user0
|
jump ebb93
|
||||||
|
|
||||||
ebb93:
|
ebb93:
|
||||||
v760 = iconst.i32 0
|
v760 = iconst.i32 0
|
||||||
@@ -54,8 +53,8 @@ ebb106(v175: i32):
|
|||||||
v180 = icmp_imm eq v179, 0
|
v180 = icmp_imm eq v179, 0
|
||||||
v183 = iconst.i32 0
|
v183 = iconst.i32 0
|
||||||
v766 = ifcmp_imm v183, -1
|
v766 = ifcmp_imm v183, -1
|
||||||
brif eq v766, ebb108
|
trapif ne v766, user0
|
||||||
trap user0
|
jump ebb108
|
||||||
|
|
||||||
ebb108:
|
ebb108:
|
||||||
v771 = iconst.i32 0
|
v771 = iconst.i32 0
|
||||||
@@ -65,8 +64,8 @@ ebb109(v184: i32):
|
|||||||
v785 = iconst.i32 0
|
v785 = iconst.i32 0
|
||||||
v193 -> v785
|
v193 -> v785
|
||||||
v791 = ifcmp_imm v193, -1
|
v791 = ifcmp_imm v193, -1
|
||||||
brif eq v791, ebb117
|
trapif ne v791, user0
|
||||||
trap user0
|
jump ebb117
|
||||||
|
|
||||||
ebb117:
|
ebb117:
|
||||||
v796 = iconst.i32 0
|
v796 = iconst.i32 0
|
||||||
@@ -77,14 +76,14 @@ ebb118(v194: i32):
|
|||||||
v809 = iconst.i32 0
|
v809 = iconst.i32 0
|
||||||
v207 -> v809
|
v207 -> v809
|
||||||
v815 = ifcmp_imm v207, -1
|
v815 = ifcmp_imm v207, -1
|
||||||
brif eq v815, ebb126
|
trapif ne v815, user0
|
||||||
trap user0
|
jump ebb126
|
||||||
|
|
||||||
ebb126:
|
ebb126:
|
||||||
v209 = iconst.i32 0
|
v209 = iconst.i32 0
|
||||||
v823 = ifcmp_imm v209, -1
|
v823 = ifcmp_imm v209, -1
|
||||||
brif eq v823, ebb129
|
trapif ne v823, user0
|
||||||
trap user0
|
jump ebb129
|
||||||
|
|
||||||
ebb129:
|
ebb129:
|
||||||
v213 = iconst.i32 -23
|
v213 = iconst.i32 -23
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
test regalloc
|
|
||||||
target i686
|
|
||||||
feature "basic-blocks"
|
|
||||||
|
|
||||||
; regex: V=v\d+
|
|
||||||
; regex: EBB=ebb\d+
|
|
||||||
|
|
||||||
; The value v9 appears both as the branch control and one of the EBB arguments
|
|
||||||
; in the brnz instruction in ebb2. It also happens that v7 and v9 are assigned
|
|
||||||
; to the same register, so v9 doesn't need to be moved before the brnz.
|
|
||||||
;
|
|
||||||
; This ended up confusong the constraint solver which had not made a record of
|
|
||||||
; the fixed register assignment for v9 since it was already in the correct
|
|
||||||
; register.
|
|
||||||
function %pr147(i32) -> i32 system_v {
|
|
||||||
ebb0(v0: i32):
|
|
||||||
v1 = iconst.i32 0
|
|
||||||
v2 = iconst.i32 1
|
|
||||||
v3 = iconst.i32 0
|
|
||||||
jump ebb2(v3, v2, v0)
|
|
||||||
|
|
||||||
; check: $(splitEdge=$EBB):
|
|
||||||
; check: jump ebb2($V, $V, v9)
|
|
||||||
|
|
||||||
ebb2(v4: i32, v5: i32, v7: i32):
|
|
||||||
; check: ebb2
|
|
||||||
v6 = iadd v4, v5
|
|
||||||
v8 = iconst.i32 -1
|
|
||||||
; v7 is killed here and v9 gets the same register.
|
|
||||||
v9 = iadd v7, v8
|
|
||||||
; check: v9 = iadd v7, v8
|
|
||||||
; Here v9 the brnz control appears to interfere with v9 the EBB argument,
|
|
||||||
; so divert_fixed_input_conflicts() calls add_var(v9), which is ok. The
|
|
||||||
; add_var sanity checks got confused when no fixed assignment could be
|
|
||||||
; found for v9.
|
|
||||||
;
|
|
||||||
; We should be able to handle this situation without making copies of v9.
|
|
||||||
brnz v9, ebb2(v5, v6, v9)
|
|
||||||
; check: brnz v9, $splitEdge
|
|
||||||
jump ebb3
|
|
||||||
|
|
||||||
ebb3:
|
|
||||||
return v5
|
|
||||||
}
|
|
||||||
|
|
||||||
function %select_i64(i64, i64, i32) -> i64 {
|
|
||||||
ebb0(v0: i64, v1: i64, v2: i32):
|
|
||||||
v3 = select v2, v0, v1
|
|
||||||
return v3
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
test regalloc
|
test regalloc
|
||||||
target i686
|
target i686
|
||||||
feature !"basic-blocks"
|
|
||||||
|
|
||||||
; regex: V=v\d+
|
; regex: V=v\d+
|
||||||
|
; regex: EBB=ebb\d+
|
||||||
|
|
||||||
; The value v9 appears both as the branch control and one of the EBB arguments
|
; The value v9 appears both as the branch control and one of the EBB arguments
|
||||||
; in the brnz instruction in ebb2. It also happens that v7 and v9 are assigned
|
; in the brnz instruction in ebb2. It also happens that v7 and v9 are assigned
|
||||||
@@ -18,13 +18,16 @@ ebb0(v0: i32):
|
|||||||
v3 = iconst.i32 0
|
v3 = iconst.i32 0
|
||||||
jump ebb2(v3, v2, v0)
|
jump ebb2(v3, v2, v0)
|
||||||
|
|
||||||
|
; check: $(splitEdge=$EBB):
|
||||||
|
; check: jump ebb2($V, $V, v9)
|
||||||
|
|
||||||
ebb2(v4: i32, v5: i32, v7: i32):
|
ebb2(v4: i32, v5: i32, v7: i32):
|
||||||
; check: ebb2
|
; check: ebb2
|
||||||
v6 = iadd v4, v5
|
v6 = iadd v4, v5
|
||||||
v8 = iconst.i32 -1
|
v8 = iconst.i32 -1
|
||||||
; v7 is killed here and v9 gets the same register.
|
; v7 is killed here and v9 gets the same register.
|
||||||
v9 = iadd v7, v8
|
v9 = iadd v7, v8
|
||||||
; check: v9 = iadd v7, v8
|
; check: v9 = iadd v7, v8
|
||||||
; Here v9 the brnz control appears to interfere with v9 the EBB argument,
|
; Here v9 the brnz control appears to interfere with v9 the EBB argument,
|
||||||
; so divert_fixed_input_conflicts() calls add_var(v9), which is ok. The
|
; so divert_fixed_input_conflicts() calls add_var(v9), which is ok. The
|
||||||
; add_var sanity checks got confused when no fixed assignment could be
|
; add_var sanity checks got confused when no fixed assignment could be
|
||||||
@@ -32,7 +35,7 @@ ebb2(v4: i32, v5: i32, v7: i32):
|
|||||||
;
|
;
|
||||||
; We should be able to handle this situation without making copies of v9.
|
; We should be able to handle this situation without making copies of v9.
|
||||||
brnz v9, ebb2(v5, v6, v9)
|
brnz v9, ebb2(v5, v6, v9)
|
||||||
; check: brnz v9, ebb2($V, $V, v9)
|
; check: brnz v9, $splitEdge
|
||||||
jump ebb3
|
jump ebb3
|
||||||
|
|
||||||
ebb3:
|
ebb3:
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
test safepoint
|
|
||||||
set enable_safepoints=true
|
|
||||||
target x86_64
|
|
||||||
feature "basic-blocks"
|
|
||||||
|
|
||||||
function %test(i32, r64, r64) -> r64 {
|
|
||||||
ebb0(v0: i32, v1:r64, v2:r64):
|
|
||||||
jump ebb1(v0)
|
|
||||||
ebb1(v3: i32):
|
|
||||||
v4 = irsub_imm v3, 1
|
|
||||||
jump ebb2(v4)
|
|
||||||
ebb2(v5: i32):
|
|
||||||
resumable_trap interrupt
|
|
||||||
brz v5, ebb1(v5)
|
|
||||||
jump ebb3
|
|
||||||
ebb3:
|
|
||||||
v6 = null.r64
|
|
||||||
v7 = is_null v6
|
|
||||||
brnz v7, ebb2(v0)
|
|
||||||
jump ebb4
|
|
||||||
ebb4:
|
|
||||||
brnz v0, ebb5
|
|
||||||
jump ebb6
|
|
||||||
ebb5:
|
|
||||||
return v1
|
|
||||||
ebb6:
|
|
||||||
return v2
|
|
||||||
}
|
|
||||||
|
|
||||||
; sameln: function %test(i32 [%rdi], r64 [%rsi], r64 [%rdx]) -> r64 [%rax] fast {
|
|
||||||
; nextln: ebb0(v0: i32 [%rdi], v1: r64 [%rsi], v2: r64 [%rdx]):
|
|
||||||
; nextln: v10 = copy v0
|
|
||||||
; nextln: jump ebb1(v10)
|
|
||||||
; nextln:
|
|
||||||
; nextln: ebb7:
|
|
||||||
; nextln: regmove.i32 v5, %rcx -> %rax
|
|
||||||
; nextln: jump ebb1(v5)
|
|
||||||
; nextln:
|
|
||||||
; nextln: ebb1(v3: i32 [%rax]):
|
|
||||||
; nextln: v8 = iconst.i32 1
|
|
||||||
; nextln: v4 = isub v8, v3
|
|
||||||
; nextln: jump ebb2(v4)
|
|
||||||
; nextln:
|
|
||||||
; nextln: ebb8:
|
|
||||||
; nextln: v9 = copy.i32 v0
|
|
||||||
; nextln: regmove v9, %rax -> %rcx
|
|
||||||
; nextln: jump ebb2(v9)
|
|
||||||
; nextln:
|
|
||||||
; nextln: ebb2(v5: i32 [%rcx]):
|
|
||||||
; nextln: safepoint v1, v2
|
|
||||||
; nextln: resumable_trap interrupt
|
|
||||||
; nextln: brz v5, ebb7
|
|
||||||
; nextln: jump ebb3
|
|
||||||
; nextln:
|
|
||||||
; nextln: ebb3:
|
|
||||||
; nextln: v6 = null.r64
|
|
||||||
; nextln: v7 = is_null v6
|
|
||||||
; nextln: brnz v7, ebb8
|
|
||||||
; nextln: jump ebb4
|
|
||||||
; nextln:
|
|
||||||
; nextln: ebb4:
|
|
||||||
; nextln: brnz.i32 v0, ebb5
|
|
||||||
; nextln: jump ebb6
|
|
||||||
; nextln:
|
|
||||||
; nextln: ebb5:
|
|
||||||
; nextln: regmove.r64 v1, %rsi -> %rax
|
|
||||||
; nextln: return v1
|
|
||||||
; nextln:
|
|
||||||
; nextln: ebb6:
|
|
||||||
; nextln: regmove.r64 v2, %rdx -> %rax
|
|
||||||
; nextln: return v2
|
|
||||||
; nextln: }
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
test safepoint
|
test safepoint
|
||||||
set enable_safepoints=true
|
set enable_safepoints=true
|
||||||
target x86_64
|
target x86_64
|
||||||
feature !"basic-blocks"
|
|
||||||
|
|
||||||
function %test(i32, r64, r64) -> r64 {
|
function %test(i32, r64, r64) -> r64 {
|
||||||
ebb0(v0: i32, v1:r64, v2:r64):
|
ebb0(v0: i32, v1:r64, v2:r64):
|
||||||
@@ -12,14 +11,18 @@ function %test(i32, r64, r64) -> r64 {
|
|||||||
ebb2(v5: i32):
|
ebb2(v5: i32):
|
||||||
resumable_trap interrupt
|
resumable_trap interrupt
|
||||||
brz v5, ebb1(v5)
|
brz v5, ebb1(v5)
|
||||||
|
jump ebb3
|
||||||
|
ebb3:
|
||||||
v6 = null.r64
|
v6 = null.r64
|
||||||
v7 = is_null v6
|
v7 = is_null v6
|
||||||
brnz v7, ebb2(v0)
|
brnz v7, ebb2(v0)
|
||||||
brnz v0, ebb3
|
|
||||||
jump ebb4
|
jump ebb4
|
||||||
ebb3:
|
|
||||||
return v1
|
|
||||||
ebb4:
|
ebb4:
|
||||||
|
brnz v0, ebb5
|
||||||
|
jump ebb6
|
||||||
|
ebb5:
|
||||||
|
return v1
|
||||||
|
ebb6:
|
||||||
return v2
|
return v2
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,28 +31,41 @@ function %test(i32, r64, r64) -> r64 {
|
|||||||
; nextln: v10 = copy v0
|
; nextln: v10 = copy v0
|
||||||
; nextln: jump ebb1(v10)
|
; nextln: jump ebb1(v10)
|
||||||
; nextln:
|
; nextln:
|
||||||
|
; nextln: ebb7:
|
||||||
|
; nextln: regmove.i32 v5, %rcx -> %rax
|
||||||
|
; nextln: jump ebb1(v5)
|
||||||
|
; nextln:
|
||||||
; nextln: ebb1(v3: i32 [%rax]):
|
; nextln: ebb1(v3: i32 [%rax]):
|
||||||
; nextln: v8 = iconst.i32 1
|
; nextln: v8 = iconst.i32 1
|
||||||
; nextln: v4 = isub v8, v3
|
; nextln: v4 = isub v8, v3
|
||||||
; nextln: jump ebb2(v4)
|
; nextln: jump ebb2(v4)
|
||||||
; nextln:
|
; nextln:
|
||||||
|
; nextln: ebb8:
|
||||||
|
; nextln: v9 = copy.i32 v0
|
||||||
|
; nextln: regmove v9, %rax -> %rcx
|
||||||
|
; nextln: jump ebb2(v9)
|
||||||
|
; nextln:
|
||||||
; nextln: ebb2(v5: i32 [%rcx]):
|
; nextln: ebb2(v5: i32 [%rcx]):
|
||||||
; nextln: safepoint v1, v2
|
; nextln: safepoint v1, v2
|
||||||
; nextln: resumable_trap interrupt
|
; nextln: resumable_trap interrupt
|
||||||
; nextln: regmove v5, %rcx -> %rax
|
; nextln: brz v5, ebb7
|
||||||
; nextln: brz v5, ebb1(v5)
|
; nextln: jump ebb3
|
||||||
; nextln: v6 = null.r64
|
|
||||||
; nextln: v7 = is_null v6
|
|
||||||
; nextln: v9 = copy.i32 v0
|
|
||||||
; nextln: brnz v7, ebb2(v9)
|
|
||||||
; nextln: brnz.i32 v0, ebb3
|
|
||||||
; nextln: jump ebb4
|
|
||||||
; nextln:
|
; nextln:
|
||||||
; nextln: ebb3:
|
; nextln: ebb3:
|
||||||
|
; nextln: v6 = null.r64
|
||||||
|
; nextln: v7 = is_null v6
|
||||||
|
; nextln: brnz v7, ebb8
|
||||||
|
; nextln: jump ebb4
|
||||||
|
; nextln:
|
||||||
|
; nextln: ebb4:
|
||||||
|
; nextln: brnz.i32 v0, ebb5
|
||||||
|
; nextln: jump ebb6
|
||||||
|
; nextln:
|
||||||
|
; nextln: ebb5:
|
||||||
; nextln: regmove.r64 v1, %rsi -> %rax
|
; nextln: regmove.r64 v1, %rsi -> %rax
|
||||||
; nextln: return v1
|
; nextln: return v1
|
||||||
; nextln:
|
; nextln:
|
||||||
; nextln: ebb4:
|
; nextln: ebb6:
|
||||||
; nextln: regmove.r64 v2, %rdx -> %rax
|
; nextln: regmove.r64 v2, %rdx -> %rax
|
||||||
; nextln: return v2
|
; nextln: return v2
|
||||||
; nextln: }
|
; nextln: }
|
||||||
|
|||||||
@@ -52,31 +52,6 @@ pub fn run(path: &Path, passes: Option<&[String]>, target: Option<&str>) -> Test
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for feature in testfile.features.iter() {
|
|
||||||
let (flag, test_expect) = match feature {
|
|
||||||
Feature::With(name) => (name, true),
|
|
||||||
Feature::Without(name) => (name, false),
|
|
||||||
};
|
|
||||||
let cranelift_has = match *flag {
|
|
||||||
// Add any cranelift feature flag here, and make sure that it is forwarded to the
|
|
||||||
// cranelift-filetest crate in the top-level Cargo.toml.
|
|
||||||
"basic-blocks" => cfg!(feature = "basic-blocks"),
|
|
||||||
_ => {
|
|
||||||
return Err(format!(
|
|
||||||
r#"{:?}: Unknown feature flag named "{}""#,
|
|
||||||
path, flag
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if cranelift_has != test_expect {
|
|
||||||
println!(
|
|
||||||
r#"skipping test {:?}: non-matching feature flag "{}""#,
|
|
||||||
path, flag
|
|
||||||
);
|
|
||||||
return Ok(started.elapsed());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if testfile.functions.is_empty() {
|
if testfile.functions.is_empty() {
|
||||||
return Err("no functions found".to_string());
|
return Err("no functions found".to_string());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,10 @@ hashbrown = { version = "0.6", optional = true }
|
|||||||
smallvec = { version = "1.0.0" }
|
smallvec = { version = "1.0.0" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std", "basic-blocks"]
|
default = ["std"]
|
||||||
std = ["cranelift-codegen/std"]
|
std = ["cranelift-codegen/std"]
|
||||||
core = ["hashbrown", "cranelift-codegen/core"]
|
core = ["hashbrown", "cranelift-codegen/core"]
|
||||||
|
|
||||||
# Temporary feature that enforces basic block semantics.
|
|
||||||
basic-blocks = ["cranelift-codegen/basic-blocks"]
|
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "experimental" }
|
maintenance = { status = "experimental" }
|
||||||
travis-ci = { repository = "bytecodealliance/cranelift" }
|
travis-ci = { repository = "bytecodealliance/cranelift" }
|
||||||
|
|||||||
@@ -480,7 +480,6 @@ impl<'a> FunctionBuilder<'a> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// In debug mode, check that all blocks are valid basic blocks.
|
// In debug mode, check that all blocks are valid basic blocks.
|
||||||
#[cfg(feature = "basic-blocks")]
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
// Iterate manually to provide more helpful error messages.
|
// Iterate manually to provide more helpful error messages.
|
||||||
|
|||||||
@@ -589,19 +589,16 @@ impl Mutator for MergeBlocks {
|
|||||||
|
|
||||||
let pred = cfg.pred_iter(ebb).next().unwrap();
|
let pred = cfg.pred_iter(ebb).next().unwrap();
|
||||||
|
|
||||||
#[cfg(feature = "basic-blocks")]
|
// If the branch instruction that lead us to this block is preceded by another branch
|
||||||
{
|
// instruction, then we have a conditional jump sequence that we should not break by
|
||||||
// If the branch instruction that lead us to this block is preceded by another branch
|
// replacing the second instruction by more of them.
|
||||||
// instruction, then we have a conditional jump sequence that we should not break by
|
if let Some(pred_pred_inst) = func.layout.prev_inst(pred.inst) {
|
||||||
// replacing the second instruction by more of them.
|
if func.dfg[pred_pred_inst].opcode().is_branch() {
|
||||||
if let Some(pred_pred_inst) = func.layout.prev_inst(pred.inst) {
|
return Some((
|
||||||
if func.dfg[pred_pred_inst].opcode().is_branch() {
|
func,
|
||||||
return Some((
|
format!("did nothing for {}", ebb),
|
||||||
func,
|
ProgressStatus::Skip,
|
||||||
format!("did nothing for {}", ebb),
|
));
|
||||||
ProgressStatus::Skip,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,11 @@ wat = "1.0.7"
|
|||||||
target-lexicon = "0.10"
|
target-lexicon = "0.10"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std", "basic-blocks"]
|
default = ["std"]
|
||||||
std = ["cranelift-codegen/std", "cranelift-frontend/std"]
|
std = ["cranelift-codegen/std", "cranelift-frontend/std"]
|
||||||
core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core"]
|
core = ["hashbrown", "cranelift-codegen/core", "cranelift-frontend/core"]
|
||||||
enable-serde = ["serde"]
|
enable-serde = ["serde"]
|
||||||
|
|
||||||
# Temporary feature that enforces basic block semantics.
|
|
||||||
basic-blocks = ["cranelift-codegen/basic-blocks", "cranelift-frontend/basic-blocks"]
|
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "experimental" }
|
maintenance = { status = "experimental" }
|
||||||
travis-ci = { repository = "bytecodealliance/cranelift" }
|
travis-ci = { repository = "bytecodealliance/cranelift" }
|
||||||
|
|||||||
@@ -205,13 +205,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
(destination, ElseData::WithElse { else_block })
|
(destination, ElseData::WithElse { else_block })
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "basic-blocks")]
|
let next_ebb = builder.create_ebb();
|
||||||
{
|
builder.ins().jump(next_ebb, &[]);
|
||||||
let next_ebb = builder.create_ebb();
|
builder.seal_block(next_ebb); // Only predecessor is the current block.
|
||||||
builder.ins().jump(next_ebb, &[]);
|
builder.switch_to_block(next_ebb);
|
||||||
builder.seal_block(next_ebb); // Only predecessor is the current block.
|
|
||||||
builder.switch_to_block(next_ebb);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here we append an argument to an Ebb targeted by an argumentless jump instruction
|
// Here we append an argument to an Ebb targeted by an argumentless jump instruction
|
||||||
// But in fact there are two cases:
|
// But in fact there are two cases:
|
||||||
@@ -1744,13 +1741,10 @@ fn translate_br_if(
|
|||||||
|
|
||||||
builder.ins().brnz(val, br_destination, inputs);
|
builder.ins().brnz(val, br_destination, inputs);
|
||||||
|
|
||||||
#[cfg(feature = "basic-blocks")]
|
let next_ebb = builder.create_ebb();
|
||||||
{
|
builder.ins().jump(next_ebb, &[]);
|
||||||
let next_ebb = builder.create_ebb();
|
builder.seal_block(next_ebb); // The only predecessor is the current block.
|
||||||
builder.ins().jump(next_ebb, &[]);
|
builder.switch_to_block(next_ebb);
|
||||||
builder.seal_block(next_ebb); // The only predecessor is the current block.
|
|
||||||
builder.switch_to_block(next_ebb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_br_if_args(
|
fn translate_br_if_args(
|
||||||
|
|||||||
Reference in New Issue
Block a user