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

View File

@@ -13,8 +13,6 @@ pub(crate) struct Formats {
pub(crate) branch_icmp: Rc<InstructionFormat>, pub(crate) branch_icmp: Rc<InstructionFormat>,
pub(crate) branch_int: Rc<InstructionFormat>, pub(crate) branch_int: Rc<InstructionFormat>,
pub(crate) branch_table: 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: Rc<InstructionFormat>,
pub(crate) call_indirect: Rc<InstructionFormat>, pub(crate) call_indirect: Rc<InstructionFormat>,
pub(crate) cond_trap: 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) float_cond_trap: Rc<InstructionFormat>,
pub(crate) func_addr: Rc<InstructionFormat>, pub(crate) func_addr: Rc<InstructionFormat>,
pub(crate) heap_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: Rc<InstructionFormat>,
pub(crate) int_compare_imm: Rc<InstructionFormat>, pub(crate) int_compare_imm: Rc<InstructionFormat>,
pub(crate) int_cond: Rc<InstructionFormat>, pub(crate) int_cond: Rc<InstructionFormat>,
@@ -172,22 +169,6 @@ impl Formats {
.imm(&entities.jump_table) .imm(&entities.jump_table)
.build(), .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") call: Builder::new("Call")
.imm(&entities.func_ref) .imm(&entities.func_ref)
.varargs() .varargs()

View File

@@ -38,26 +38,6 @@ fn define_control_flow(
.is_branch(true), .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( let Testable = &TypeVar::new(
"Testable", "Testable",
"A scalar boolean or integer type", "A scalar boolean or integer type",
@@ -214,68 +194,6 @@ fn define_control_flow(
TypeSetBuilder::new().ints(32..64).refs(32..64).build(), 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( ig.push(
Inst::new( Inst::new(
"debugtrap", "debugtrap",
@@ -1880,156 +1798,6 @@ pub(crate) fn define(
.operands_out(vec![a]), .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 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 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`"); 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()); 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 // 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(_branch) = inst_iter.next() {
if let Some(next) = inst_iter.next() { if let Some(next) = inst_iter.next() {
match dfg[next].opcode() { match dfg[next].opcode() {
Opcode::Fallthrough | Opcode::Jump => (), Opcode::Jump => (),
_ => return Err((next, "post-branch instruction not fallthrough or jump")), _ => return Err((next, "post-branch instruction not jump")),
} }
} }
} }

View File

@@ -229,7 +229,6 @@ impl InstructionData {
Self::BranchTable { Self::BranchTable {
table, destination, .. table, destination, ..
} => BranchInfo::Table(table, Some(destination)), } => BranchInfo::Table(table, Some(destination)),
Self::IndirectJump { table, .. } => BranchInfo::Table(table, None),
_ => { _ => {
debug_assert!(!self.opcode().is_branch()); debug_assert!(!self.opcode().is_branch());
BranchInfo::NotABranch BranchInfo::NotABranch
@@ -248,7 +247,7 @@ impl InstructionData {
| Self::BranchInt { destination, .. } | Self::BranchInt { destination, .. }
| Self::BranchFloat { destination, .. } | Self::BranchFloat { destination, .. }
| Self::BranchIcmp { destination, .. } => Some(destination), | Self::BranchIcmp { destination, .. } => Some(destination),
Self::BranchTable { .. } | Self::IndirectJump { .. } => None, Self::BranchTable { .. } => None,
_ => { _ => {
debug_assert!(!self.opcode().is_branch()); debug_assert!(!self.opcode().is_branch());
None None
@@ -282,7 +281,7 @@ impl InstructionData {
ref mut destination, ref mut destination,
.. ..
} => Some(destination), } => Some(destination),
Self::BranchTable { .. } | Self::IndirectJump { .. } => None, Self::BranchTable { .. } => None,
_ => { _ => {
debug_assert!(!self.opcode().is_branch()); debug_assert!(!self.opcode().is_branch());
None None
@@ -297,8 +296,7 @@ impl InstructionData {
&InstructionData::UnaryBool { imm, .. } => Some(DataValue::from(imm)), &InstructionData::UnaryBool { imm, .. } => Some(DataValue::from(imm)),
// 8-bit. // 8-bit.
&InstructionData::BinaryImm8 { imm, .. } &InstructionData::BinaryImm8 { imm, .. }
| &InstructionData::TernaryImm8 { imm, .. } | &InstructionData::TernaryImm8 { imm, .. } => Some(DataValue::from(imm as i8)), // Note the switch from unsigned to signed.
| &InstructionData::BranchTableEntry { imm, .. } => Some(DataValue::from(imm as i8)), // Note the switch from unsigned to signed.
// 32-bit // 32-bit
&InstructionData::UnaryIeee32 { imm, .. } => Some(DataValue::from(imm)), &InstructionData::UnaryIeee32 { imm, .. } => Some(DataValue::from(imm)),
&InstructionData::HeapAddr { 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 => { Opcode::Debugtrap => {
ctx.emit(Inst::Brk); 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 => { Opcode::Trapz | Opcode::Trapnz | Opcode::ResumableTrapnz => {
panic!("trapz / trapnz / resumable_trapnz should have been removed by legalization!"); 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)); 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::Jump
| Opcode::Fallthrough
| Opcode::Brz | Opcode::Brz
| Opcode::Brnz | Opcode::Brnz
| Opcode::BrIcmp | Opcode::BrIcmp
| Opcode::Brif | Opcode::Brif
| Opcode::Brff | Opcode::Brff
| Opcode::IndirectJumpTableBr
| Opcode::BrTable => { | Opcode::BrTable => {
panic!("Branch opcode reached non-branch lowering logic!"); 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 op0 = ctx.data(branches[0]).opcode();
let op1 = ctx.data(branches[1]).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 taken = BranchTarget::Label(targets[0]);
// not_taken target is the target of the second branch, even if it is a Fallthrough // 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 // 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. // Must be an unconditional branch or an indirect branch.
let op = ctx.data(branches[0]).opcode(); let op = ctx.data(branches[0]).opcode();
match op { match op {
Opcode::Jump | Opcode::Fallthrough => { Opcode::Jump => {
assert!(branches.len() == 1); 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 { ctx.emit(Inst::Jump {
dest: BranchTarget::Label(targets[0]), dest: BranchTarget::Label(targets[0]),
}); });

View File

@@ -542,10 +542,9 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
) -> CodegenResult<()> { ) -> CodegenResult<()> {
// A block should end with at most two branches. The first may be a // 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 // conditional branch; a conditional branch can be followed only by an
// unconditional branch or fallthrough. Otherwise, if only one branch, // unconditional branch. Otherwise, if only one branch, it may be an
// it may be an unconditional branch, a fallthrough, a return, or a // unconditional branch, a return, or a trap. These conditions are verified
// trap. These conditions are verified by `is_ebb_basic()` during the // by `is_ebb_basic()` during the verifier pass.
// verifier pass.
assert!(branches.len() <= 2); assert!(branches.len() <= 2);
if 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 op0 = ctx.data(branches[0]).opcode();
let op1 = ctx.data(branches[1]).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 taken = BranchTarget::Label(targets[0]);
let not_taken = BranchTarget::Label(targets[1]); 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. // Must be an unconditional branch or an indirect branch.
let op = ctx.data(branches[0]).opcode(); let op = ctx.data(branches[0]).opcode();
match op { match op {
Opcode::Jump | Opcode::Fallthrough => { Opcode::Jump => {
assert_eq!(branches.len(), 1); 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 { ctx.emit(Inst::Jump {
dest: BranchTarget::Label(targets[0]), 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::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::Ifcmp
| Opcode::Ffcmp | Opcode::Ffcmp
| Opcode::Trapff | Opcode::Trapff
@@ -2909,25 +2898,15 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} }
Opcode::Jump Opcode::Jump
| Opcode::Fallthrough
| Opcode::Brz | Opcode::Brz
| Opcode::Brnz | Opcode::Brnz
| Opcode::BrIcmp | Opcode::BrIcmp
| Opcode::Brif | Opcode::Brif
| Opcode::Brff | Opcode::Brff
| Opcode::IndirectJumpTableBr
| Opcode::BrTable => { | Opcode::BrTable => {
panic!("Branch opcode reached non-branch lowering logic!"); 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::IaddImm
| Opcode::ImulImm | Opcode::ImulImm
| Opcode::UdivImm | Opcode::UdivImm
@@ -2984,7 +2963,7 @@ fn lower_branch<C: LowerCtx<I = Inst>>(
let op0 = ctx.data(branches[0]).opcode(); let op0 = ctx.data(branches[0]).opcode();
let op1 = ctx.data(branches[1]).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 taken = BranchTarget::Label(targets[0]);
let not_taken = BranchTarget::Label(targets[1]); 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. // Must be an unconditional branch or an indirect branch.
let op = ctx.data(branches[0]).opcode(); let op = ctx.data(branches[0]).opcode();
match op { match op {
Opcode::Jump | Opcode::Fallthrough => { Opcode::Jump => {
assert!(branches.len() == 1); 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 { ctx.emit(Inst::Jump {
dest: BranchTarget::Label(targets[0]), 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!"); panic!("table_addr should have been removed by legalization!");
} }
Opcode::Safepoint => { Opcode::Copy => {
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 => {
panic!("Unused opcode should not be encountered."); 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 => { Opcode::Trapz | Opcode::Trapnz | Opcode::ResumableTrapnz => {
panic!("trapz / trapnz / resumable_trapnz should have been removed by legalization!"); panic!("trapz / trapnz / resumable_trapnz should have been removed by legalization!");
} }
Opcode::Jump Opcode::Jump
| Opcode::Fallthrough
| Opcode::Brz | Opcode::Brz
| Opcode::Brnz | Opcode::Brnz
| Opcode::BrIcmp | Opcode::BrIcmp
| Opcode::Brif | Opcode::Brif
| Opcode::Brff | Opcode::Brff
| Opcode::IndirectJumpTableBr
| Opcode::BrTable => { | Opcode::BrTable => {
panic!("Branch opcode reached non-branch lowering logic!"); panic!("Branch opcode reached non-branch lowering logic!");
} }
@@ -6936,13 +6918,10 @@ impl LowerBackend for X64Backend {
op0, op0,
op1 op1
); );
assert!(op1 == Opcode::Jump || op1 == Opcode::Fallthrough); assert!(op1 == Opcode::Jump);
let taken = targets[0]; let taken = targets[0];
// not_taken target is the target of the second branch, even if it is a Fallthrough // not_taken target is the target of the second branch.
// 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.
let not_taken = targets[1]; let not_taken = targets[1];
match op0 { match op0 {
@@ -7094,23 +7073,6 @@ impl LowerBackend for X64Backend {
let cond_code = emit_cmp(ctx, ifcmp, cond_code); let cond_code = emit_cmp(ctx, ifcmp, cond_code);
let cc = CC::from_intcc(cond_code); let cc = CC::from_intcc(cond_code);
ctx.emit(Inst::jmp_cond(cc, taken, not_taken)); 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 { } else {
// Should be disallowed by flags checks in verifier. // Should be disallowed by flags checks in verifier.
unimplemented!("Brif with non-ifcmp input"); unimplemented!("Brif with non-ifcmp input");
@@ -7152,7 +7114,7 @@ impl LowerBackend for X64Backend {
// Must be an unconditional branch or trap. // Must be an unconditional branch or trap.
let op = ctx.data(branches[0]).opcode(); let op = ctx.data(branches[0]).opcode();
match op { match op {
Opcode::Jump | Opcode::Fallthrough => { Opcode::Jump => {
ctx.emit(Inst::jmp_known(targets[0])); 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) { 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) { for inst in f.layout.block_likely_branches(block) {
if f.dfg[inst].opcode().is_branch() { 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)>( fn visit_branch_targets<F: FnMut(Inst, Block)>(f: &Function, inst: Inst, visit: &mut F) {
f: &Function, match f.dfg[inst].analyze_branch(&f.dfg.value_lists) {
block: Block, BranchInfo::NotABranch => {}
inst: Inst, BranchInfo::SingleDest(dest, _) => {
visit: &mut F, visit(inst, dest);
) { }
if f.dfg[inst].opcode() == Opcode::Fallthrough { BranchInfo::Table(table, maybe_dest) => {
visit(inst, f.layout.next_block(block).unwrap()); if let Some(dest) = maybe_dest {
} else {
match f.dfg[inst].analyze_branch(&f.dfg.value_lists) {
BranchInfo::NotABranch => {}
BranchInfo::SingleDest(dest, _) => {
visit(inst, dest); visit(inst, dest);
} }
BranchInfo::Table(table, maybe_dest) => { for &dest in f.jump_tables[table].as_slice() {
if let Some(dest) = maybe_dest { visit(inst, dest);
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! { peepmatic_traits::define_parse_and_typing_rules_for_operator! {
Opcode { Opcode {
adjust_sp_down => AdjustSpDown {
parameters(iNN);
result(void);
}
adjust_sp_down_imm => AdjustSpDownImm {
immediates(iNN);
result(void);
}
band => Band { band => Band {
parameters(iNN, iNN); parameters(iNN, iNN);
result(iNN); result(iNN);
@@ -888,10 +880,6 @@ unsafe impl<'a, 'b> InstructionSet<'b> for &'a dyn TargetIsa {
} }
InstructionData::Unary { InstructionData::Unary {
opcode: opcode @ Opcode::AdjustSpDown,
arg,
}
| InstructionData::Unary {
opcode: opcode @ Opcode::Bint, opcode: opcode @ Opcode::Bint,
arg, arg,
} }
@@ -920,10 +908,6 @@ unsafe impl<'a, 'b> InstructionSet<'b> for &'a dyn TargetIsa {
} }
InstructionData::UnaryImm { InstructionData::UnaryImm {
opcode: opcode @ Opcode::AdjustSpDownImm,
imm,
}
| InstructionData::UnaryImm {
opcode: opcode @ Opcode::Iconst, opcode: opcode @ Opcode::Iconst,
imm, imm,
} => { } => {
@@ -949,15 +933,6 @@ unsafe impl<'a, 'b> InstructionSet<'b> for &'a dyn TargetIsa {
let root = root.resolve_inst(&pos.func.dfg).unwrap(); let root = root.resolve_inst(&pos.func.dfg).unwrap();
match operator { 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 => { Opcode::Bconst => {
let c = a.unwrap_constant(); let c = a.unwrap_constant();
let val = const_to_value(pos.ins(), c, root); let val = const_to_value(pos.ins(), c, root);

View File

@@ -82,9 +82,6 @@
(fits-in-native-word $C)) (fits-in-native-word $C))
(irsub_imm $C $x)) (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)`. ;; 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)) (=> (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)) (=> (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 } => { InstructionData::BinaryImm64 { opcode, arg, imm } => {
let ty = pos.func.dfg.ctrl_typevar(inst); 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::entities::AnyEntity;
use crate::ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint}; use crate::ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint};
use crate::ir::{ use crate::ir::{
types, ArgumentPurpose, Block, Constant, FuncRef, Function, GlobalValue, Inst, InstructionData, types, ArgumentPurpose, Block, Constant, FuncRef, Function, GlobalValue, Inst, JumpTable,
JumpTable, Opcode, SigRef, StackSlot, Type, Value, ValueDef, ValueList, Opcode, SigRef, StackSlot, Type, Value, ValueDef, ValueList,
}; };
use crate::isa::TargetIsa; use crate::isa::TargetIsa;
use crate::iterators::IteratorExtras; use crate::iterators::IteratorExtras;
@@ -663,11 +663,6 @@ impl<'a> Verifier<'a> {
self.verify_block(inst, destination, errors)?; self.verify_block(inst, destination, errors)?;
self.verify_jump_table(inst, table, errors)?; self.verify_jump_table(inst, table, errors)?;
} }
BranchTableBase { table, .. }
| BranchTableEntry { table, .. }
| IndirectJump { table, .. } => {
self.verify_jump_table(inst, table, errors)?;
}
Call { Call {
func_ref, ref args, .. func_ref, ref args, ..
} => { } => {
@@ -1221,9 +1216,6 @@ impl<'a> Verifier<'a> {
let _ = self.typecheck_return(inst, errors); let _ = self.typecheck_return(inst, errors);
let _ = self.typecheck_special(inst, ctrl_type, errors); let _ = self.typecheck_special(inst, ctrl_type, errors);
// Misuses of copy_nop instructions are fatal
self.typecheck_copy_nop(inst, errors)?;
Ok(()) Ok(())
} }
@@ -1555,36 +1547,6 @@ impl<'a> Verifier<'a> {
Ok(()) 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( fn cfg_integrity(
&self, &self,
cfg: &ControlFlowGraph, 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<()> { fn typecheck_function_signature(&self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
self.func self.func
.signature .signature
@@ -1787,7 +1731,6 @@ impl<'a> Verifier<'a> {
for inst in self.func.layout.block_insts(block) { for inst in self.func.layout.block_insts(block) {
self.block_integrity(block, inst, errors)?; self.block_integrity(block, inst, errors)?;
self.instruction_integrity(inst, errors)?; self.instruction_integrity(inst, errors)?;
self.verify_safepoint_unused(inst, errors)?;
self.typecheck(inst, errors)?; self.typecheck(inst, errors)?;
self.immediate_constraints(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, table,
.. ..
} => write!(w, " {}, {}, {}", arg, destination, 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 { Call {
func_ref, ref args, .. func_ref, ref args, ..
} => write!(w, " {}({})", func_ref, DisplayValues(args.as_slice(pool))), } => 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: block0:
v0 = iconst.i64 1 v0 = iconst.i64 1
v1 = jump_table_base.i64 jt0 br_table v0, block1, jt0
v2 = jump_table_entry.i64 v0, v1, 4, jt0
v3 = iadd v1, v2
indirect_jump_table_br v3, jt0
block1: block1:
return return

View File

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

View File

@@ -29,18 +29,3 @@ block0:
; check: v5 = trueif eq v4 ; check: v5 = trueif eq v4
return v6 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. // Interpret a Cranelift instruction.
Ok(match inst.opcode() { Ok(match inst.opcode() {
Opcode::Jump | Opcode::Fallthrough => ControlFlow::ContinueAt(branch(), args()?), Opcode::Jump => ControlFlow::ContinueAt(branch(), args()?),
Opcode::Brz => branch_when( Opcode::Brz => branch_when(
!arg(0)? !arg(0)?
.convert(ValueConversionKind::ToBoolean)? .convert(ValueConversionKind::ToBoolean)?
@@ -448,15 +448,6 @@ where
assign(Value::or(mask_a, mask_b)?) assign(Value::or(mask_a, mask_b)?)
} }
Opcode::Copy => assign(arg(0)?), 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( Opcode::Icmp => assign(icmp(
ctrl_ty, ctrl_ty,
inst.cond_code().unwrap(), inst.cond_code().unwrap(),
@@ -1026,10 +1017,6 @@ where
assign(vectorizelanes(&new_vec, ctrl_ty)?) assign(vectorizelanes(&new_vec, ctrl_ty)?)
} }
Opcode::IaddPairwise => assign(binary_pairwise(arg(0)?, arg(1)?, ctrl_ty, Value::add)?), 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] #[test]
fn regression_9() { fn regression_9() {
interp( interp(

View File

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

View File

@@ -2676,34 +2676,6 @@ impl<'a> Parser<'a> {
table, 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 => { InstructionFormat::TernaryImm8 => {
let lhs = self.match_value("expected SSA value first operand")?; let lhs = self.match_value("expected SSA value first operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?; self.match_token(Token::Comma, "expected ',' between operands")?;