Merge pull request #3446 from bjorn3/remove_old_insts

Remove many unused instructions
This commit is contained in:
Pat Hickey
2021-10-13 07:46:44 -07:00
committed by GitHub
24 changed files with 37 additions and 616 deletions

View File

@@ -70,8 +70,6 @@ pub(crate) struct InstructionContent {
pub is_terminator: bool,
/// True for all branch or jump instructions.
pub is_branch: bool,
/// True for all indirect branch or jump instructions.',
pub is_indirect_branch: bool,
/// Is this a call instruction?
pub is_call: bool,
/// Is this a return instruction?
@@ -145,7 +143,6 @@ pub(crate) struct InstructionBuilder {
// See Instruction comments for the meaning of these fields.
is_terminator: bool,
is_branch: bool,
is_indirect_branch: bool,
is_call: bool,
is_return: bool,
is_ghost: bool,
@@ -168,7 +165,6 @@ impl InstructionBuilder {
is_terminator: false,
is_branch: false,
is_indirect_branch: false,
is_call: false,
is_return: false,
is_ghost: false,
@@ -210,12 +206,6 @@ impl InstructionBuilder {
self
}
#[allow(clippy::wrong_self_convention)]
pub fn is_indirect_branch(mut self, val: bool) -> Self {
self.is_indirect_branch = val;
self
}
#[allow(clippy::wrong_self_convention)]
pub fn is_call(mut self, val: bool) -> Self {
self.is_call = val;
@@ -300,7 +290,6 @@ impl InstructionBuilder {
imm_opnums,
is_terminator: self.is_terminator,
is_branch: self.is_branch,
is_indirect_branch: self.is_indirect_branch,
is_call: self.is_call,
is_return: self.is_return,
is_ghost: self.is_ghost,

View File

@@ -468,13 +468,6 @@ fn gen_opcodes(all_inst: &AllInstructions, fmt: &mut Formatter) {
"True for all branch or jump instructions.",
fmt,
);
gen_bool_accessor(
all_inst,
|inst| inst.is_indirect_branch,
"is_indirect_branch",
"True for all indirect branch or jump instructions.",
fmt,
);
gen_bool_accessor(
all_inst,
|inst| inst.is_call,

View File

@@ -13,8 +13,6 @@ pub(crate) struct Formats {
pub(crate) branch_icmp: Rc<InstructionFormat>,
pub(crate) branch_int: Rc<InstructionFormat>,
pub(crate) branch_table: Rc<InstructionFormat>,
pub(crate) branch_table_base: Rc<InstructionFormat>,
pub(crate) branch_table_entry: Rc<InstructionFormat>,
pub(crate) call: Rc<InstructionFormat>,
pub(crate) call_indirect: Rc<InstructionFormat>,
pub(crate) cond_trap: Rc<InstructionFormat>,
@@ -23,7 +21,6 @@ pub(crate) struct Formats {
pub(crate) float_cond_trap: Rc<InstructionFormat>,
pub(crate) func_addr: Rc<InstructionFormat>,
pub(crate) heap_addr: Rc<InstructionFormat>,
pub(crate) indirect_jump: Rc<InstructionFormat>,
pub(crate) int_compare: Rc<InstructionFormat>,
pub(crate) int_compare_imm: Rc<InstructionFormat>,
pub(crate) int_cond: Rc<InstructionFormat>,
@@ -172,22 +169,6 @@ impl Formats {
.imm(&entities.jump_table)
.build(),
branch_table_entry: Builder::new("BranchTableEntry")
.value()
.value()
.imm(&imm.uimm8)
.imm(&entities.jump_table)
.build(),
branch_table_base: Builder::new("BranchTableBase")
.imm(&entities.jump_table)
.build(),
indirect_jump: Builder::new("IndirectJump")
.value()
.imm(&entities.jump_table)
.build(),
call: Builder::new("Call")
.imm(&entities.func_ref)
.varargs()

View File

@@ -38,26 +38,6 @@ fn define_control_flow(
.is_branch(true),
);
ig.push(
Inst::new(
"fallthrough",
r#"
Fall through to the next block.
This is the same as `jump`, except the destination block must be
the next one in the layout.
Jumps are turned into fall-through instructions by the branch
relaxation pass. There is no reason to use this instruction outside
that pass.
"#,
&formats.jump,
)
.operands_in(vec![block, args])
.is_terminator(true)
.is_branch(true),
);
let Testable = &TypeVar::new(
"Testable",
"A scalar boolean or integer type",
@@ -214,68 +194,6 @@ fn define_control_flow(
TypeSetBuilder::new().ints(32..64).refs(32..64).build(),
);
{
let x = &Operand::new("x", iAddr).with_doc("index into jump table");
let addr = &Operand::new("addr", iAddr);
let Size = &Operand::new("Size", &imm.uimm8).with_doc("Size in bytes");
let JT = &Operand::new("JT", &entities.jump_table);
let entry = &Operand::new("entry", iAddr).with_doc("entry of jump table");
ig.push(
Inst::new(
"jump_table_entry",
r#"
Get an entry from a jump table.
Load a serialized ``entry`` from a jump table ``JT`` at a given index
``addr`` with a specific ``Size``. The retrieved entry may need to be
decoded after loading, depending upon the jump table type used.
Currently, the only type supported is entries which are relative to the
base of the jump table.
"#,
&formats.branch_table_entry,
)
.operands_in(vec![x, addr, Size, JT])
.operands_out(vec![entry])
.can_load(true),
);
ig.push(
Inst::new(
"jump_table_base",
r#"
Get the absolute base address of a jump table.
This is used for jump tables wherein the entries are stored relative to
the base of jump table. In order to use these, generated code should first
load an entry using ``jump_table_entry``, then use this instruction to add
the relative base back to it.
"#,
&formats.branch_table_base,
)
.operands_in(vec![JT])
.operands_out(vec![addr]),
);
ig.push(
Inst::new(
"indirect_jump_table_br",
r#"
Branch indirectly via a jump table entry.
Unconditionally jump via a jump table entry that was previously loaded
with the ``jump_table_entry`` instruction.
"#,
&formats.indirect_jump,
)
.operands_in(vec![addr, JT])
.is_indirect_branch(true)
.is_terminator(true)
.is_branch(true),
);
}
ig.push(
Inst::new(
"debugtrap",
@@ -1880,156 +1798,6 @@ pub(crate) fn define(
.operands_out(vec![a]),
);
ig.push(
Inst::new(
"spill",
r#"
Spill a register value to a stack slot.
This instruction behaves exactly like `copy`, but the result
value is assigned to a spill slot.
"#,
&formats.unary,
)
.operands_in(vec![x])
.operands_out(vec![a])
.can_store(true),
);
ig.push(
Inst::new(
"fill",
r#"
Load a register value from a stack slot.
This instruction behaves exactly like `copy`, but creates a new
SSA value for the spilled input value.
"#,
&formats.unary,
)
.operands_in(vec![x])
.operands_out(vec![a])
.can_load(true),
);
ig.push(
Inst::new(
"fill_nop",
r#"
This is identical to `fill`, except it has no encoding, since it is a no-op.
This instruction is created only during late-stage redundant-reload removal, after all
registers and stack slots have been assigned. It is used to replace `fill`s that have
been identified as redundant.
"#,
&formats.unary,
)
.operands_in(vec![x])
.operands_out(vec![a])
.can_load(true),
);
ig.push(
Inst::new(
"copy_nop",
r#"
Stack-slot-to-the-same-stack-slot copy, which is guaranteed to turn
into a no-op. This instruction is for use only within Cranelift itself.
This instruction copies its input, preserving the value type.
"#,
&formats.unary,
)
.operands_in(vec![x])
.operands_out(vec![a]),
);
let delta = &Operand::new("delta", Int);
ig.push(
Inst::new(
"adjust_sp_down",
r#"
Subtracts ``delta`` offset value from the stack pointer register.
This instruction is used to adjust the stack pointer by a dynamic amount.
"#,
&formats.unary,
)
.operands_in(vec![delta])
.other_side_effects(true),
);
let Offset = &Operand::new("Offset", &imm.imm64).with_doc("Offset from current stack pointer");
ig.push(
Inst::new(
"adjust_sp_up_imm",
r#"
Adds ``Offset`` immediate offset value to the stack pointer register.
This instruction is used to adjust the stack pointer, primarily in function
prologues and epilogues. ``Offset`` is constrained to the size of a signed
32-bit integer.
"#,
&formats.unary_imm,
)
.operands_in(vec![Offset])
.other_side_effects(true),
);
let Offset = &Operand::new("Offset", &imm.imm64).with_doc("Offset from current stack pointer");
ig.push(
Inst::new(
"adjust_sp_down_imm",
r#"
Subtracts ``Offset`` immediate offset value from the stack pointer
register.
This instruction is used to adjust the stack pointer, primarily in function
prologues and epilogues. ``Offset`` is constrained to the size of a signed
32-bit integer.
"#,
&formats.unary_imm,
)
.operands_in(vec![Offset])
.other_side_effects(true),
);
let f = &Operand::new("f", iflags);
ig.push(
Inst::new(
"ifcmp_sp",
r#"
Compare ``addr`` with the stack pointer and set the CPU flags.
This is like `ifcmp` where ``addr`` is the LHS operand and the stack
pointer is the RHS.
"#,
&formats.unary,
)
.operands_in(vec![addr])
.operands_out(vec![f]),
);
let N =
&Operand::new("args", &entities.varargs).with_doc("Variable number of args for StackMap");
ig.push(
Inst::new(
"safepoint",
r#"
This instruction will provide live reference values at a point in
the function. It can only be used by the compiler.
"#,
&formats.multiary,
)
.operands_in(vec![N])
.other_side_effects(true),
);
let x = &Operand::new("x", TxN).with_doc("Vector to split");
let lo = &Operand::new("lo", &TxN.half_vector()).with_doc("Low-numbered lanes of `x`");
let hi = &Operand::new("hi", &TxN.half_vector()).with_doc("High-numbered lanes of `x`");

View File

@@ -274,12 +274,12 @@ impl Function {
let mut inst_iter = inst_iter.skip_while(|&inst| !dfg[inst].opcode().is_branch());
// A conditional branch is permitted in a basic block only when followed
// by a terminal jump or fallthrough instruction.
// by a terminal jump instruction.
if let Some(_branch) = inst_iter.next() {
if let Some(next) = inst_iter.next() {
match dfg[next].opcode() {
Opcode::Fallthrough | Opcode::Jump => (),
_ => return Err((next, "post-branch instruction not fallthrough or jump")),
Opcode::Jump => (),
_ => return Err((next, "post-branch instruction not jump")),
}
}
}

View File

@@ -229,7 +229,6 @@ impl InstructionData {
Self::BranchTable {
table, destination, ..
} => BranchInfo::Table(table, Some(destination)),
Self::IndirectJump { table, .. } => BranchInfo::Table(table, None),
_ => {
debug_assert!(!self.opcode().is_branch());
BranchInfo::NotABranch
@@ -248,7 +247,7 @@ impl InstructionData {
| Self::BranchInt { destination, .. }
| Self::BranchFloat { destination, .. }
| Self::BranchIcmp { destination, .. } => Some(destination),
Self::BranchTable { .. } | Self::IndirectJump { .. } => None,
Self::BranchTable { .. } => None,
_ => {
debug_assert!(!self.opcode().is_branch());
None
@@ -282,7 +281,7 @@ impl InstructionData {
ref mut destination,
..
} => Some(destination),
Self::BranchTable { .. } | Self::IndirectJump { .. } => None,
Self::BranchTable { .. } => None,
_ => {
debug_assert!(!self.opcode().is_branch());
None
@@ -297,8 +296,7 @@ impl InstructionData {
&InstructionData::UnaryBool { imm, .. } => Some(DataValue::from(imm)),
// 8-bit.
&InstructionData::BinaryImm8 { imm, .. }
| &InstructionData::TernaryImm8 { imm, .. }
| &InstructionData::BranchTableEntry { imm, .. } => Some(DataValue::from(imm as i8)), // Note the switch from unsigned to signed.
| &InstructionData::TernaryImm8 { imm, .. } => Some(DataValue::from(imm as i8)), // Note the switch from unsigned to signed.
// 32-bit
&InstructionData::UnaryIeee32 { imm, .. } => Some(DataValue::from(imm)),
&InstructionData::HeapAddr { imm, .. } => {

View File

@@ -2029,10 +2029,6 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
}
}
Opcode::JumpTableEntry | Opcode::JumpTableBase => {
panic!("Should not appear: we handle BrTable directly");
}
Opcode::Debugtrap => {
ctx.emit(Inst::Brk);
}
@@ -2076,10 +2072,6 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
});
}
Opcode::Safepoint => {
panic!("safepoint instructions not used by new backend's safepoints!");
}
Opcode::Trapz | Opcode::Trapnz | Opcode::ResumableTrapnz => {
panic!("trapz / trapnz / resumable_trapnz should have been removed by legalization!");
}
@@ -2162,25 +2154,12 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(Inst::gen_move(writable_xreg(PINNED_REG), rm, I64));
}
Opcode::Spill
| Opcode::Fill
| Opcode::FillNop
| Opcode::CopyNop
| Opcode::AdjustSpDown
| Opcode::AdjustSpUpImm
| Opcode::AdjustSpDownImm
| Opcode::IfcmpSp => {
panic!("Unused opcode should not be encountered.");
}
Opcode::Jump
| Opcode::Fallthrough
| Opcode::Brz
| Opcode::Brnz
| Opcode::BrIcmp
| Opcode::Brif
| Opcode::Brff
| Opcode::IndirectJumpTableBr
| Opcode::BrTable => {
panic!("Branch opcode reached non-branch lowering logic!");
}
@@ -3794,7 +3773,7 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
let op0 = ctx.data(branches[0]).opcode();
let op1 = ctx.data(branches[1]).opcode();
assert!(op1 == Opcode::Jump || op1 == Opcode::Fallthrough);
assert!(op1 == Opcode::Jump);
let taken = BranchTarget::Label(targets[0]);
// not_taken target is the target of the second branch, even if it is a Fallthrough
// instruction: because we reorder blocks while we lower, the fallthrough in the new
@@ -3937,11 +3916,8 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
// Must be an unconditional branch or an indirect branch.
let op = ctx.data(branches[0]).opcode();
match op {
Opcode::Jump | Opcode::Fallthrough => {
Opcode::Jump => {
assert!(branches.len() == 1);
// In the Fallthrough case, the machine-independent driver
// fills in `targets[0]` with our fallthrough block, so this
// is valid for both Jump and Fallthrough.
ctx.emit(Inst::Jump {
dest: BranchTarget::Label(targets[0]),
});

View File

@@ -542,10 +542,9 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
) -> CodegenResult<()> {
// A block should end with at most two branches. The first may be a
// conditional branch; a conditional branch can be followed only by an
// unconditional branch or fallthrough. Otherwise, if only one branch,
// it may be an unconditional branch, a fallthrough, a return, or a
// trap. These conditions are verified by `is_ebb_basic()` during the
// verifier pass.
// unconditional branch. Otherwise, if only one branch, it may be an
// unconditional branch, a return, or a trap. These conditions are verified
// by `is_ebb_basic()` during the verifier pass.
assert!(branches.len() <= 2);
if branches.len() == 2 {
@@ -553,7 +552,7 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
let op0 = ctx.data(branches[0]).opcode();
let op1 = ctx.data(branches[1]).opcode();
assert!(op1 == Opcode::Jump || op1 == Opcode::Fallthrough);
assert!(op1 == Opcode::Jump);
let taken = BranchTarget::Label(targets[0]);
let not_taken = BranchTarget::Label(targets[1]);
@@ -586,11 +585,8 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
// Must be an unconditional branch or an indirect branch.
let op = ctx.data(branches[0]).opcode();
match op {
Opcode::Jump | Opcode::Fallthrough => {
Opcode::Jump => {
assert_eq!(branches.len(), 1);
// In the Fallthrough case, the machine-independent driver
// fills in `targets[0]` with our fallthrough block, so this
// is valid for both Jump and Fallthrough.
ctx.emit(Inst::Jump {
dest: BranchTarget::Label(targets[0]),
});

View File

@@ -2888,17 +2888,6 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
Opcode::Isplit | Opcode::Iconcat => unimplemented!("Wide integer ops not implemented."),
Opcode::Spill
| Opcode::Fill
| Opcode::FillNop
| Opcode::CopyNop
| Opcode::AdjustSpDown
| Opcode::AdjustSpUpImm
| Opcode::AdjustSpDownImm
| Opcode::IfcmpSp => {
panic!("Unused opcode should not be encountered.");
}
Opcode::Ifcmp
| Opcode::Ffcmp
| Opcode::Trapff
@@ -2909,25 +2898,15 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
}
Opcode::Jump
| Opcode::Fallthrough
| Opcode::Brz
| Opcode::Brnz
| Opcode::BrIcmp
| Opcode::Brif
| Opcode::Brff
| Opcode::IndirectJumpTableBr
| Opcode::BrTable => {
panic!("Branch opcode reached non-branch lowering logic!");
}
Opcode::JumpTableEntry | Opcode::JumpTableBase => {
panic!("Should not appear: we handle BrTable directly");
}
Opcode::Safepoint => {
panic!("safepoint instructions not used by new backend's safepoints!");
}
Opcode::IaddImm
| Opcode::ImulImm
| Opcode::UdivImm
@@ -2984,7 +2963,7 @@ fn lower_branch<C: LowerCtx<I = Inst>>(
let op0 = ctx.data(branches[0]).opcode();
let op1 = ctx.data(branches[1]).opcode();
assert!(op1 == Opcode::Jump || op1 == Opcode::Fallthrough);
assert!(op1 == Opcode::Jump);
let taken = BranchTarget::Label(targets[0]);
let not_taken = BranchTarget::Label(targets[1]);
@@ -3033,11 +3012,8 @@ fn lower_branch<C: LowerCtx<I = Inst>>(
// Must be an unconditional branch or an indirect branch.
let op = ctx.data(branches[0]).opcode();
match op {
Opcode::Jump | Opcode::Fallthrough => {
Opcode::Jump => {
assert!(branches.len() == 1);
// In the Fallthrough case, the machine-independent driver
// fills in `targets[0]` with our fallthrough block, so this
// is valid for both Jump and Fallthrough.
ctx.emit(Inst::Jump {
dest: BranchTarget::Label(targets[0]),
});

View File

@@ -6858,38 +6858,20 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
panic!("table_addr should have been removed by legalization!");
}
Opcode::Safepoint => {
panic!("safepoint instructions not used by new backend's safepoints!");
}
Opcode::Spill
| Opcode::Fill
| Opcode::FillNop
| Opcode::CopyNop
| Opcode::AdjustSpDown
| Opcode::AdjustSpUpImm
| Opcode::AdjustSpDownImm
| Opcode::IfcmpSp
| Opcode::Copy => {
Opcode::Copy => {
panic!("Unused opcode should not be encountered.");
}
Opcode::JumpTableEntry | Opcode::JumpTableBase => {
panic!("Should not appear: we handle BrTable directly");
}
Opcode::Trapz | Opcode::Trapnz | Opcode::ResumableTrapnz => {
panic!("trapz / trapnz / resumable_trapnz should have been removed by legalization!");
}
Opcode::Jump
| Opcode::Fallthrough
| Opcode::Brz
| Opcode::Brnz
| Opcode::BrIcmp
| Opcode::Brif
| Opcode::Brff
| Opcode::IndirectJumpTableBr
| Opcode::BrTable => {
panic!("Branch opcode reached non-branch lowering logic!");
}
@@ -6936,13 +6918,10 @@ impl LowerBackend for X64Backend {
op0,
op1
);
assert!(op1 == Opcode::Jump || op1 == Opcode::Fallthrough);
assert!(op1 == Opcode::Jump);
let taken = targets[0];
// not_taken target is the target of the second branch, even if it is a Fallthrough
// instruction: because we reorder blocks while we lower, the fallthrough in the new
// order is not (necessarily) the same as the fallthrough in CLIF. So we use the
// explicitly-provided target.
// not_taken target is the target of the second branch.
let not_taken = targets[1];
match op0 {
@@ -7094,23 +7073,6 @@ impl LowerBackend for X64Backend {
let cond_code = emit_cmp(ctx, ifcmp, cond_code);
let cc = CC::from_intcc(cond_code);
ctx.emit(Inst::jmp_cond(cc, taken, not_taken));
} else if let Some(ifcmp_sp) = matches_input(ctx, flag_input, Opcode::IfcmpSp) {
let operand = put_input_in_reg(
ctx,
InsnInput {
insn: ifcmp_sp,
input: 0,
},
);
let ty = ctx.input_ty(ifcmp_sp, 0);
ctx.emit(Inst::cmp_rmi_r(
OperandSize::from_ty(ty),
RegMemImm::reg(regs::rsp()),
operand,
));
let cond_code = ctx.data(branches[0]).cond_code().unwrap();
let cc = CC::from_intcc(cond_code);
ctx.emit(Inst::jmp_cond(cc, taken, not_taken));
} else {
// Should be disallowed by flags checks in verifier.
unimplemented!("Brif with non-ifcmp input");
@@ -7152,7 +7114,7 @@ impl LowerBackend for X64Backend {
// Must be an unconditional branch or trap.
let op = ctx.data(branches[0]).opcode();
match op {
Opcode::Jump | Opcode::Fallthrough => {
Opcode::Jump => {
ctx.emit(Inst::jmp_known(targets[0]));
}

View File

@@ -1295,32 +1295,23 @@ impl<'func, I: VCodeInst> LowerCtx for Lower<'func, I> {
pub(crate) fn visit_block_succs<F: FnMut(Inst, Block)>(f: &Function, block: Block, mut visit: F) {
for inst in f.layout.block_likely_branches(block) {
if f.dfg[inst].opcode().is_branch() {
visit_branch_targets(f, block, inst, &mut visit);
visit_branch_targets(f, inst, &mut visit);
}
}
}
fn visit_branch_targets<F: FnMut(Inst, Block)>(
f: &Function,
block: Block,
inst: Inst,
visit: &mut F,
) {
if f.dfg[inst].opcode() == Opcode::Fallthrough {
visit(inst, f.layout.next_block(block).unwrap());
} else {
match f.dfg[inst].analyze_branch(&f.dfg.value_lists) {
BranchInfo::NotABranch => {}
BranchInfo::SingleDest(dest, _) => {
fn visit_branch_targets<F: FnMut(Inst, Block)>(f: &Function, inst: Inst, visit: &mut F) {
match f.dfg[inst].analyze_branch(&f.dfg.value_lists) {
BranchInfo::NotABranch => {}
BranchInfo::SingleDest(dest, _) => {
visit(inst, dest);
}
BranchInfo::Table(table, maybe_dest) => {
if let Some(dest) = maybe_dest {
visit(inst, dest);
}
BranchInfo::Table(table, maybe_dest) => {
if let Some(dest) = maybe_dest {
visit(inst, dest);
}
for &dest in f.jump_tables[table].as_slice() {
visit(inst, dest);
}
for &dest in f.jump_tables[table].as_slice() {
visit(inst, dest);
}
}
}

View File

@@ -26,14 +26,6 @@ use std::sync::atomic::{AtomicPtr, Ordering};
peepmatic_traits::define_parse_and_typing_rules_for_operator! {
Opcode {
adjust_sp_down => AdjustSpDown {
parameters(iNN);
result(void);
}
adjust_sp_down_imm => AdjustSpDownImm {
immediates(iNN);
result(void);
}
band => Band {
parameters(iNN, iNN);
result(iNN);
@@ -888,10 +880,6 @@ unsafe impl<'a, 'b> InstructionSet<'b> for &'a dyn TargetIsa {
}
InstructionData::Unary {
opcode: opcode @ Opcode::AdjustSpDown,
arg,
}
| InstructionData::Unary {
opcode: opcode @ Opcode::Bint,
arg,
}
@@ -920,10 +908,6 @@ unsafe impl<'a, 'b> InstructionSet<'b> for &'a dyn TargetIsa {
}
InstructionData::UnaryImm {
opcode: opcode @ Opcode::AdjustSpDownImm,
imm,
}
| InstructionData::UnaryImm {
opcode: opcode @ Opcode::Iconst,
imm,
} => {
@@ -949,15 +933,6 @@ unsafe impl<'a, 'b> InstructionSet<'b> for &'a dyn TargetIsa {
let root = root.resolve_inst(&pos.func.dfg).unwrap();
match operator {
Opcode::AdjustSpDown => {
let a = part_to_value(pos, root, a).unwrap();
pos.ins().adjust_sp_down(a).into()
}
Opcode::AdjustSpDownImm => {
let c = a.unwrap_constant();
let imm = Imm64::try_from(c).unwrap();
pos.ins().adjust_sp_down_imm(imm).into()
}
Opcode::Bconst => {
let c = a.unwrap_constant();
let val = const_to_value(pos.ins(), c, root);

View File

@@ -82,9 +82,6 @@
(fits-in-native-word $C))
(irsub_imm $C $x))
;; Unary instructions whose operand is constant.
(=> (adjust_sp_down $C) (adjust_sp_down_imm $C))
;; Fold `(binop_imm $C1 (binop_imm $C2 $x))` into `(binop_imm $(binop $C2 $C1) $x)`.
(=> (iadd_imm $C1 (iadd_imm $C2 $x)) (iadd_imm $(iadd $C1 $C2) $x))
(=> (imul_imm $C1 (imul_imm $C2 $x)) (imul_imm $(imul $C1 $C2) $x))

View File

@@ -809,15 +809,6 @@ mod simplify {
}
}
InstructionData::Unary { opcode, arg } => {
if let Opcode::AdjustSpDown = opcode {
if let Some(imm) = resolve_imm64_value(&pos.func.dfg, arg) {
// Note this works for both positive and negative immediate values.
pos.func.dfg.replace(inst).adjust_sp_down_imm(imm);
}
}
}
InstructionData::BinaryImm64 { opcode, arg, imm } => {
let ty = pos.func.dfg.ctrl_typevar(inst);

View File

@@ -65,8 +65,8 @@ use crate::ir;
use crate::ir::entities::AnyEntity;
use crate::ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint};
use crate::ir::{
types, ArgumentPurpose, Block, Constant, FuncRef, Function, GlobalValue, Inst, InstructionData,
JumpTable, Opcode, SigRef, StackSlot, Type, Value, ValueDef, ValueList,
types, ArgumentPurpose, Block, Constant, FuncRef, Function, GlobalValue, Inst, JumpTable,
Opcode, SigRef, StackSlot, Type, Value, ValueDef, ValueList,
};
use crate::isa::TargetIsa;
use crate::iterators::IteratorExtras;
@@ -663,11 +663,6 @@ impl<'a> Verifier<'a> {
self.verify_block(inst, destination, errors)?;
self.verify_jump_table(inst, table, errors)?;
}
BranchTableBase { table, .. }
| BranchTableEntry { table, .. }
| IndirectJump { table, .. } => {
self.verify_jump_table(inst, table, errors)?;
}
Call {
func_ref, ref args, ..
} => {
@@ -1221,9 +1216,6 @@ impl<'a> Verifier<'a> {
let _ = self.typecheck_return(inst, errors);
let _ = self.typecheck_special(inst, ctrl_type, errors);
// Misuses of copy_nop instructions are fatal
self.typecheck_copy_nop(inst, errors)?;
Ok(())
}
@@ -1555,36 +1547,6 @@ impl<'a> Verifier<'a> {
Ok(())
}
fn typecheck_copy_nop(
&self,
inst: Inst,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
if let InstructionData::Unary {
opcode: Opcode::CopyNop,
arg,
} = self.func.dfg[inst]
{
let dst_vals = self.func.dfg.inst_results(inst);
if dst_vals.len() != 1 {
return errors.fatal((
inst,
self.context(inst),
"copy_nop must produce exactly one result",
));
}
let dst_val = dst_vals[0];
if self.func.dfg.value_type(dst_val) != self.func.dfg.value_type(arg) {
return errors.fatal((
inst,
self.context(inst),
"copy_nop src and dst types must be the same",
));
}
}
Ok(())
}
fn cfg_integrity(
&self,
cfg: &ControlFlowGraph,
@@ -1706,24 +1668,6 @@ impl<'a> Verifier<'a> {
}
}
fn verify_safepoint_unused(
&self,
inst: Inst,
errors: &mut VerifierErrors,
) -> VerifierStepResult<()> {
if let Some(isa) = self.isa {
if !isa.flags().enable_safepoints() && self.func.dfg[inst].opcode() == Opcode::Safepoint
{
return errors.fatal((
inst,
self.context(inst),
"safepoint instruction cannot be used when it is not enabled.",
));
}
}
Ok(())
}
fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
self.func
.signature
@@ -1787,7 +1731,6 @@ impl<'a> Verifier<'a> {
for inst in self.func.layout.block_insts(block) {
self.block_integrity(block, inst, errors)?;
self.instruction_integrity(inst, errors)?;
self.verify_safepoint_unused(inst, errors)?;
self.typecheck(inst, errors)?;
self.immediate_constraints(inst, errors)?;
}

View File

@@ -462,11 +462,6 @@ pub fn write_operands(w: &mut dyn Write, dfg: &DataFlowGraph, inst: Inst) -> fmt
table,
..
} => write!(w, " {}, {}, {}", arg, destination, table),
BranchTableBase { table, .. } => write!(w, " {}", table),
BranchTableEntry {
args, imm, table, ..
} => write!(w, " {}, {}, {}, {}", args[0], args[1], imm, table),
IndirectJump { arg, table, .. } => write!(w, " {}, {}", arg, table),
Call {
func_ref, ref args, ..
} => write!(w, " {}({})", func_ref, DisplayValues(args.as_slice(pool))),

View File

@@ -1,34 +0,0 @@
test licm
target aarch64
target x86_64
function %dont_hoist_jump_table_entry_during_licm() {
jt0 = jump_table [block1, block1]
block0:
fallthrough block1
block1: ; the loop!
v2 = iconst.i32 42
v3 = ifcmp_imm v2, 0
brif uge v3, block1
fallthrough block2
block2:
v1 = iconst.i64 -14
v8 = ifcmp_imm v1, 2
brif uge v8, block1
jump block3
block3:
v5 = jump_table_base.i64 jt0
v6 = jump_table_entry.i64 v1, v5, 4, jt0
v7 = iadd v5, v6
indirect_jump_table_br v7, jt0
; check: block2:
; nextln: v8 = ifcmp_imm.i64 v1, 2
; nextln: brif uge v8, block1
; nextln: jump block3
; check: block3:
; nextln: jump_table_entry.i64
}

View File

@@ -6,10 +6,7 @@ function %rewrite_jump_table() {
block0:
v0 = iconst.i64 1
v1 = jump_table_base.i64 jt0
v2 = jump_table_entry.i64 v0, v1, 4, jt0
v3 = iadd v1, v2
indirect_jump_table_br v3, jt0
br_table v0, block1, jt0
block1:
return

View File

@@ -6,12 +6,12 @@ block0(v0: i32):
v1 = icmp_imm ule v0, 2
v2 = iconst.i32 1
brnz v1, block3(v2) ; handle base case, n <= 2
fallthrough block1(v0, v2)
jump block1(v0, v2)
block1(v4: i32, v5:i32):
v6 = iconst.i32 1
v7 = iadd_imm v4, -2
fallthrough block2(v7, v5, v6)
jump block2(v7, v5, v6)
block2(v10: i32, v11: i32, v12: i32): ; params: n, fib(n-1), fib(n-2)
v13 = iadd v11, v12
@@ -40,7 +40,7 @@ function %fibonacci_recursive(i32) -> i32 {
block0(v0: i32):
v1 = icmp_imm ule v0, 2
brnz v1, block2
fallthrough block1(v0)
jump block1(v0)
block1(v10: i32):
v11 = iadd_imm v10, -1

View File

@@ -29,18 +29,3 @@ block0:
; check: v5 = trueif eq v4
return v6
}
function %spill() -> i32 {
block0:
v0 = iconst.i32 7
v1 = spill v0
v2 = fill v1
v3 = spill v0
v4 = fill v1
v5 = bor v2, v4
; check: v1 = spill v0
; check: v2 = fill v1
; check: v3 = spill v0
; check: v4 = fill v1
return v5
}

View File

@@ -221,7 +221,7 @@ where
// Interpret a Cranelift instruction.
Ok(match inst.opcode() {
Opcode::Jump | Opcode::Fallthrough => ControlFlow::ContinueAt(branch(), args()?),
Opcode::Jump => ControlFlow::ContinueAt(branch(), args()?),
Opcode::Brz => branch_when(
!arg(0)?
.convert(ValueConversionKind::ToBoolean)?
@@ -448,15 +448,6 @@ where
assign(Value::or(mask_a, mask_b)?)
}
Opcode::Copy => assign(arg(0)?),
Opcode::Spill => unimplemented!("Spill"),
Opcode::Fill => unimplemented!("Fill"),
Opcode::FillNop => assign(arg(0)?),
Opcode::CopyNop => unimplemented!("CopyNop"),
Opcode::AdjustSpDown => unimplemented!("AdjustSpDown"),
Opcode::AdjustSpUpImm => unimplemented!("AdjustSpUpImm"),
Opcode::AdjustSpDownImm => unimplemented!("AdjustSpDownImm"),
Opcode::IfcmpSp => unimplemented!("IfcmpSp"),
Opcode::Safepoint => unimplemented!("Safepoint"),
Opcode::Icmp => assign(icmp(
ctrl_ty,
inst.cond_code().unwrap(),
@@ -1026,10 +1017,6 @@ where
assign(vectorizelanes(&new_vec, ctrl_ty)?)
}
Opcode::IaddPairwise => assign(binary_pairwise(arg(0)?, arg(1)?, ctrl_ty, Value::add)?),
Opcode::JumpTableBase | Opcode::JumpTableEntry | Opcode::IndirectJumpTableBr => {
unimplemented!("Legacy instruction: {}", inst.opcode())
}
})
}

View File

@@ -324,15 +324,6 @@ mod tests {
);
}
#[test]
fn regression_8() {
interp(
b"
(=> (adjust_sp_down $C) (adjust_sp_down_imm $C))
",
);
}
#[test]
fn regression_9() {
interp(

View File

@@ -6,14 +6,6 @@
peepmatic_traits::define_operator! {
/// A `TOperator` type for use inside tests.
TestOperator {
adjust_sp_down => AdjustSpDown {
parameters(iNN);
result(void);
}
adjust_sp_down_imm => AdjustSpDownImm {
immediates(iNN);
result(void);
}
band => Band {
parameters(iNN, iNN);
result(iNN);

View File

@@ -2676,34 +2676,6 @@ impl<'a> Parser<'a> {
table,
}
}
InstructionFormat::BranchTableBase => {
let table = self.match_jt()?;
ctx.check_jt(table, self.loc)?;
InstructionData::BranchTableBase { opcode, table }
}
InstructionFormat::BranchTableEntry => {
let index = self.match_value("expected SSA value operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?;
let base = self.match_value("expected SSA value operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?;
let imm = self.match_uimm8("expected width")?;
self.match_token(Token::Comma, "expected ',' between operands")?;
let table = self.match_jt()?;
ctx.check_jt(table, self.loc)?;
InstructionData::BranchTableEntry {
opcode,
args: [index, base],
imm,
table,
}
}
InstructionFormat::IndirectJump => {
let arg = self.match_value("expected SSA value operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?;
let table = self.match_jt()?;
ctx.check_jt(table, self.loc)?;
InstructionData::IndirectJump { opcode, arg, table }
}
InstructionFormat::TernaryImm8 => {
let lhs = self.match_value("expected SSA value first operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?;