AArch64: avoid branches with explicit offsets at lowering stage.

In discussions with @bnjbvr, it came up that generating `OneWayCondBr`s
with explicit, hardcoded PC-offsets as part of lowered instruction
sequences is actually unsafe, because the register allocator *might*
insert a spill or reload into the middle of our sequence. We were
careful about this in some cases but somehow missed that it was a
general restriction. Conceptually, all inter-instruction references
should be via labels at the VCode level; explicit offsets are only ever
known at emission time, and resolved by the `MachBuffer`.

To allow for conditional trap checks without modifying the CFG (as seen
by regalloc) during lowering, this PR instead adds a `TrapIf`
pseudo-instruction that conditionally skips a single embedded trap
instruction. It lowers to the same `condbr label ; trap ; label: ...`
sequence, but without the hardcoded branch-target offset in the lowering
code.
This commit is contained in:
Chris Fallin
2020-07-01 16:28:41 -07:00
parent f2dd1535d5
commit b7ecad1d74
11 changed files with 267 additions and 312 deletions

View File

@@ -631,14 +631,11 @@ impl AArch64ABIBody {
rn: stack_reg(), rn: stack_reg(),
rm: stack_limit, rm: stack_limit,
}); });
insts.push(Inst::OneWayCondBr { insts.push(Inst::TrapIf {
target: BranchTarget::ResolvedOffset(8),
// Here `Hs` == "higher or same" when interpreting the two
// operands as unsigned integers.
kind: CondBrKind::Cond(Cond::Hs),
});
insts.push(Inst::Udf {
trap_info: (ir::SourceLoc::default(), ir::TrapCode::StackOverflow), trap_info: (ir::SourceLoc::default(), ir::TrapCode::StackOverflow),
// Here `Lo` == "less than" when interpreting the two
// operands as unsigned integers.
kind: CondBrKind::Cond(Cond::Lo),
}); });
} }
} }

View File

@@ -1471,12 +1471,20 @@ impl MachInstEmit for Inst {
} }
sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero())); sink.put4(enc_jump26(0b000101, not_taken.as_offset26_or_zero()));
} }
&Inst::OneWayCondBr { target, kind } => { &Inst::TrapIf { kind, trap_info } => {
// condbr KIND, LABEL
let off = sink.cur_offset(); let off = sink.cur_offset();
if let Some(l) = target.as_label() { let label = sink.get_label();
sink.use_label_at_offset(off, l, LabelUse::Branch19); sink.put4(enc_conditional_br(
} BranchTarget::Label(label),
sink.put4(enc_conditional_br(target, kind)); kind.invert(),
));
sink.use_label_at_offset(off, label, LabelUse::Branch19);
// udf
let trap = Inst::Udf { trap_info };
trap.emit(sink, flags, state);
// LABEL:
sink.bind_label(label);
} }
&Inst::IndirectBr { rn, .. } => { &Inst::IndirectBr { rn, .. } => {
sink.put4(enc_br(rn)); sink.put4(enc_br(rn));
@@ -1515,6 +1523,17 @@ impl MachInstEmit for Inst {
// emission time, because we cannot allow the regalloc to insert spills/reloads in // emission time, because we cannot allow the regalloc to insert spills/reloads in
// the middle; we depend on hardcoded PC-rel addressing below. // the middle; we depend on hardcoded PC-rel addressing below.
// Branch to default when condition code from prior comparison indicates.
let br = enc_conditional_br(info.default_target, CondBrKind::Cond(Cond::Hs));
// No need to inform the sink's branch folding logic about this branch, because it
// will not be merged with any other branch, flipped, or elided (it is not preceded
// or succeeded by any other branch). Just emit it with the label use.
let default_br_offset = sink.cur_offset();
if let BranchTarget::Label(l) = info.default_target {
sink.use_label_at_offset(default_br_offset, l, LabelUse::Branch19);
}
sink.put4(br);
// Save index in a tmp (the live range of ridx only goes to start of this // Save index in a tmp (the live range of ridx only goes to start of this
// sequence; rtmp1 or rtmp2 may overwrite it). // sequence; rtmp1 or rtmp2 may overwrite it).
let inst = Inst::gen_move(rtmp2, ridx, I64); let inst = Inst::gen_move(rtmp2, ridx, I64);

View File

@@ -2505,149 +2505,148 @@ fn test_aarch64_binemit() {
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Zero(xreg(8)),
},
"080200B4",
"cbz x8, 64",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::NotZero(xreg(8)), kind: CondBrKind::NotZero(xreg(8)),
}, },
"080200B5", "480000B40000A0D4",
"cbnz x8, 64", "cbz x8, 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Eq), kind: CondBrKind::Zero(xreg(8)),
}, },
"00020054", "480000B50000A0D4",
"b.eq 64", "cbnz x8, 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Ne), kind: CondBrKind::Cond(Cond::Ne),
}, },
"01020054", "400000540000A0D4",
"b.ne 64", "b.eq 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Hs), kind: CondBrKind::Cond(Cond::Eq),
}, },
"02020054", "410000540000A0D4",
"b.hs 64", "b.ne 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Lo), kind: CondBrKind::Cond(Cond::Lo),
}, },
"03020054", "420000540000A0D4",
"b.lo 64", "b.hs 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Mi), kind: CondBrKind::Cond(Cond::Hs),
}, },
"04020054", "430000540000A0D4",
"b.mi 64", "b.lo 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Pl), kind: CondBrKind::Cond(Cond::Pl),
}, },
"05020054", "440000540000A0D4",
"b.pl 64", "b.mi 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Vs), kind: CondBrKind::Cond(Cond::Mi),
}, },
"06020054", "450000540000A0D4",
"b.vs 64", "b.pl 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Vc), kind: CondBrKind::Cond(Cond::Vc),
}, },
"07020054", "460000540000A0D4",
"b.vc 64", "b.vs 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Hi), kind: CondBrKind::Cond(Cond::Vs),
}, },
"08020054", "470000540000A0D4",
"b.hi 64", "b.vc 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Ls), kind: CondBrKind::Cond(Cond::Ls),
}, },
"09020054", "480000540000A0D4",
"b.ls 64", "b.hi 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Ge), kind: CondBrKind::Cond(Cond::Hi),
}, },
"0A020054", "490000540000A0D4",
"b.ge 64", "b.ls 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Lt), kind: CondBrKind::Cond(Cond::Lt),
}, },
"0B020054", "4A0000540000A0D4",
"b.lt 64", "b.ge 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Gt), kind: CondBrKind::Cond(Cond::Ge),
}, },
"0C020054", "4B0000540000A0D4",
"b.gt 64", "b.lt 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Le), kind: CondBrKind::Cond(Cond::Le),
}, },
"0D020054", "4C0000540000A0D4",
"b.le 64", "b.gt 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Al), kind: CondBrKind::Cond(Cond::Gt),
}, },
"0E020054", "4D0000540000A0D4",
"b.al 64", "b.le 8 ; udf",
)); ));
insns.push(( insns.push((
Inst::OneWayCondBr { Inst::TrapIf {
target: BranchTarget::ResolvedOffset(64), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Nv), kind: CondBrKind::Cond(Cond::Nv),
}, },
"0F020054", "4E0000540000A0D4",
"b.nv 64", "b.al 8 ; udf",
));
insns.push((
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Al),
},
"4F0000540000A0D4",
"b.nv 8 ; udf",
)); ));
insns.push(( insns.push((

View File

@@ -334,6 +334,7 @@ pub struct CallIndInfo {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct JTSequenceInfo { pub struct JTSequenceInfo {
pub targets: Vec<BranchTarget>, pub targets: Vec<BranchTarget>,
pub default_target: BranchTarget,
pub targets_for_term: Vec<MachLabel>, // needed for MachTerminator. pub targets_for_term: Vec<MachLabel>, // needed for MachTerminator.
} }
@@ -817,20 +818,17 @@ pub enum Inst {
kind: CondBrKind, kind: CondBrKind,
}, },
/// A one-way conditional branch, invisible to the CFG processing; used *only* as part of /// A conditional trap: execute a `udf` if the condition is true. This is
/// straight-line sequences in code to be emitted. /// one VCode instruction because it uses embedded control flow; it is
/// logically a single-in, single-out region, but needs to appear as one
/// unit to the register allocator.
/// ///
/// In more detail: /// The `CondBrKind` gives the conditional-branch condition that will
/// - This branch is lowered to a branch at the machine-code level, but does not end a basic /// *execute* the embedded `Inst`. (In the emitted code, we use the inverse
/// block, and does not create edges in the CFG seen by regalloc. /// of this condition in a branch that skips the trap instruction.)
/// - Thus, it is *only* valid to use as part of a single-in, single-out sequence that is TrapIf {
/// lowered from a single CLIF instruction. For example, certain arithmetic operations may
/// use these branches to handle certain conditions, such as overflows, traps, etc.
///
/// See, e.g., the lowering of `trapif` (conditional trap) for an example.
OneWayCondBr {
target: BranchTarget,
kind: CondBrKind, kind: CondBrKind,
trap_info: (SourceLoc, TrapCode),
}, },
/// An indirect branch through a register, augmented with set of all /// An indirect branch through a register, augmented with set of all
@@ -1346,7 +1344,7 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
collector.add_defs(&*info.defs); collector.add_defs(&*info.defs);
collector.add_use(info.rn); collector.add_use(info.rn);
} }
&Inst::CondBr { ref kind, .. } | &Inst::OneWayCondBr { ref kind, .. } => match kind { &Inst::CondBr { ref kind, .. } => match kind {
CondBrKind::Zero(rt) | CondBrKind::NotZero(rt) => { CondBrKind::Zero(rt) | CondBrKind::NotZero(rt) => {
collector.add_use(*rt); collector.add_use(*rt);
} }
@@ -1358,6 +1356,12 @@ fn aarch64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
&Inst::Nop0 | Inst::Nop4 => {} &Inst::Nop0 | Inst::Nop4 => {}
&Inst::Brk => {} &Inst::Brk => {}
&Inst::Udf { .. } => {} &Inst::Udf { .. } => {}
&Inst::TrapIf { ref kind, .. } => match kind {
CondBrKind::Zero(rt) | CondBrKind::NotZero(rt) => {
collector.add_use(*rt);
}
CondBrKind::Cond(_) => {}
},
&Inst::Adr { rd, .. } => { &Inst::Adr { rd, .. } => {
collector.add_def(rd); collector.add_def(rd);
} }
@@ -1949,13 +1953,16 @@ fn aarch64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
} }
map_use(mapper, &mut info.rn); map_use(mapper, &mut info.rn);
} }
&mut Inst::CondBr { ref mut kind, .. } | &mut Inst::OneWayCondBr { ref mut kind, .. } => { &mut Inst::CondBr { ref mut kind, .. } => {
map_br(mapper, kind); map_br(mapper, kind);
} }
&mut Inst::IndirectBr { ref mut rn, .. } => { &mut Inst::IndirectBr { ref mut rn, .. } => {
map_use(mapper, rn); map_use(mapper, rn);
} }
&mut Inst::Nop0 | &mut Inst::Nop4 | &mut Inst::Brk | &mut Inst::Udf { .. } => {} &mut Inst::Nop0 | &mut Inst::Nop4 | &mut Inst::Brk | &mut Inst::Udf { .. } => {}
&mut Inst::TrapIf { ref mut kind, .. } => {
map_br(mapper, kind);
}
&mut Inst::Adr { ref mut rd, .. } => { &mut Inst::Adr { ref mut rd, .. } => {
map_def(mapper, rd); map_def(mapper, rd);
} }
@@ -2026,10 +2033,6 @@ impl MachInst for Inst {
&Inst::CondBr { &Inst::CondBr {
taken, not_taken, .. taken, not_taken, ..
} => MachTerminator::Cond(taken.as_label().unwrap(), not_taken.as_label().unwrap()), } => MachTerminator::Cond(taken.as_label().unwrap(), not_taken.as_label().unwrap()),
&Inst::OneWayCondBr { .. } => {
// Explicitly invisible to CFG processing.
MachTerminator::None
}
&Inst::IndirectBr { ref targets, .. } => MachTerminator::Indirect(&targets[..]), &Inst::IndirectBr { ref targets, .. } => MachTerminator::Indirect(&targets[..]),
&Inst::JTSequence { ref info, .. } => { &Inst::JTSequence { ref info, .. } => {
MachTerminator::Indirect(&info.targets_for_term[..]) MachTerminator::Indirect(&info.targets_for_term[..])
@@ -2880,32 +2883,26 @@ impl ShowWithRRU for Inst {
} }
} }
} }
&Inst::OneWayCondBr {
ref target,
ref kind,
} => {
let target = target.show_rru(mb_rru);
match kind {
&CondBrKind::Zero(reg) => {
let reg = reg.show_rru(mb_rru);
format!("cbz {}, {}", reg, target)
}
&CondBrKind::NotZero(reg) => {
let reg = reg.show_rru(mb_rru);
format!("cbnz {}, {}", reg, target)
}
&CondBrKind::Cond(c) => {
let c = c.show_rru(mb_rru);
format!("b.{} {}", c, target)
}
}
}
&Inst::IndirectBr { rn, .. } => { &Inst::IndirectBr { rn, .. } => {
let rn = rn.show_rru(mb_rru); let rn = rn.show_rru(mb_rru);
format!("br {}", rn) format!("br {}", rn)
} }
&Inst::Brk => "brk #0".to_string(), &Inst::Brk => "brk #0".to_string(),
&Inst::Udf { .. } => "udf".to_string(), &Inst::Udf { .. } => "udf".to_string(),
&Inst::TrapIf { ref kind, .. } => match kind {
&CondBrKind::Zero(reg) => {
let reg = reg.show_rru(mb_rru);
format!("cbnz {}, 8 ; udf", reg)
}
&CondBrKind::NotZero(reg) => {
let reg = reg.show_rru(mb_rru);
format!("cbz {}, 8 ; udf", reg)
}
&CondBrKind::Cond(c) => {
let c = c.invert().show_rru(mb_rru);
format!("b.{} 8 ; udf", c)
}
},
&Inst::Adr { rd, off } => { &Inst::Adr { rd, off } => {
let rd = rd.show_rru(mb_rru); let rd = rd.show_rru(mb_rru);
format!("adr {}, pc+{}", rd, off) format!("adr {}, pc+{}", rd, off)
@@ -2922,15 +2919,26 @@ impl ShowWithRRU for Inst {
let ridx = ridx.show_rru(mb_rru); let ridx = ridx.show_rru(mb_rru);
let rtmp1 = rtmp1.show_rru(mb_rru); let rtmp1 = rtmp1.show_rru(mb_rru);
let rtmp2 = rtmp2.show_rru(mb_rru); let rtmp2 = rtmp2.show_rru(mb_rru);
let default_target = info.default_target.show_rru(mb_rru);
format!( format!(
concat!( concat!(
"b.hs {} ; ",
"adr {}, pc+16 ; ", "adr {}, pc+16 ; ",
"ldrsw {}, [{}, {}, LSL 2] ; ", "ldrsw {}, [{}, {}, LSL 2] ; ",
"add {}, {}, {} ; ", "add {}, {}, {} ; ",
"br {} ; ", "br {} ; ",
"jt_entries {:?}" "jt_entries {:?}"
), ),
rtmp1, rtmp2, rtmp1, ridx, rtmp1, rtmp1, rtmp2, rtmp1, info.targets default_target,
rtmp1,
rtmp2,
rtmp1,
ridx,
rtmp1,
rtmp1,
rtmp2,
rtmp1,
info.targets
) )
} }
&Inst::LoadConst64 { rd, const_data } => { &Inst::LoadConst64 { rd, const_data } => {

View File

@@ -282,14 +282,11 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
// msub rd, rd, rm, rn ; rd = rn - rd * rm // msub rd, rd, rm, rn ; rd = rn - rd * rm
// Check for divide by 0. // Check for divide by 0.
let branch_size = 8;
ctx.emit(Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(branch_size),
kind: CondBrKind::NotZero(rm),
});
let trap_info = (ctx.srcloc(insn), TrapCode::IntegerDivisionByZero); let trap_info = (ctx.srcloc(insn), TrapCode::IntegerDivisionByZero);
ctx.emit(Inst::Udf { trap_info }); ctx.emit(Inst::TrapIf {
trap_info,
kind: CondBrKind::Zero(rm),
});
ctx.emit(Inst::AluRRRR { ctx.emit(Inst::AluRRRR {
alu_op: ALUOp::MSub64, alu_op: ALUOp::MSub64,
@@ -300,17 +297,17 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
}); });
} else { } else {
if div_op == ALUOp::SDiv64 { if div_op == ALUOp::SDiv64 {
// cbz rm, #20 // cbnz rm, #8
// udf ; divide by zero
// cmn rm, 1 // cmn rm, 1
// ccmp rn, 1, #nzcv, eq // ccmp rn, 1, #nzcv, eq
// b.vc 12 // b.vc #8
// udf ; signed overflow // udf ; signed overflow
// udf ; divide by zero
// Check for divide by 0. // Check for divide by 0.
let branch_size = 20; let trap_info = (ctx.srcloc(insn), TrapCode::IntegerDivisionByZero);
ctx.emit(Inst::OneWayCondBr { ctx.emit(Inst::TrapIf {
target: BranchTarget::ResolvedOffset(branch_size), trap_info,
kind: CondBrKind::Zero(rm), kind: CondBrKind::Zero(rm),
}); });
@@ -336,27 +333,22 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
nzcv: NZCV::new(false, false, false, false), nzcv: NZCV::new(false, false, false, false),
cond: Cond::Eq, cond: Cond::Eq,
}); });
ctx.emit(Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(12),
kind: CondBrKind::Cond(Cond::Vc),
});
let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow); let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow);
ctx.emit(Inst::Udf { trap_info }); ctx.emit(Inst::TrapIf {
trap_info,
kind: CondBrKind::Cond(Cond::Vs),
});
} else { } else {
// cbnz rm, #8 // cbnz rm, #8
// udf ; divide by zero // udf ; divide by zero
// Check for divide by 0. // Check for divide by 0.
let branch_size = 8; let trap_info = (ctx.srcloc(insn), TrapCode::IntegerDivisionByZero);
ctx.emit(Inst::OneWayCondBr { ctx.emit(Inst::TrapIf {
target: BranchTarget::ResolvedOffset(branch_size), trap_info,
kind: CondBrKind::NotZero(rm), kind: CondBrKind::Zero(rm),
}); });
} }
let trap_info = (ctx.srcloc(insn), TrapCode::IntegerDivisionByZero);
ctx.emit(Inst::Udf { trap_info });
} }
} }
@@ -1324,15 +1316,10 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
cond cond
}; };
// Branch around the break instruction with inverted cond. Go straight to lowered ctx.emit(Inst::TrapIf {
// one-target form; this is logically part of a single-in single-out template lowering. trap_info,
let cond = cond.invert();
ctx.emit(Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(8),
kind: CondBrKind::Cond(cond), kind: CondBrKind::Cond(cond),
}); });
ctx.emit(Inst::Udf { trap_info })
} }
Opcode::Safepoint => { Opcode::Safepoint => {
@@ -1711,12 +1698,11 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
} else { } else {
ctx.emit(Inst::FpuCmp64 { rn, rm: rn }); ctx.emit(Inst::FpuCmp64 { rn, rm: rn });
} }
ctx.emit(Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(8),
kind: CondBrKind::Cond(lower_fp_condcode(FloatCC::Ordered)),
});
let trap_info = (ctx.srcloc(insn), TrapCode::BadConversionToInteger); let trap_info = (ctx.srcloc(insn), TrapCode::BadConversionToInteger);
ctx.emit(Inst::Udf { trap_info }); ctx.emit(Inst::TrapIf {
trap_info,
kind: CondBrKind::Cond(lower_fp_condcode(FloatCC::Unordered)),
});
let tmp = ctx.alloc_tmp(RegClass::V128, I128); let tmp = ctx.alloc_tmp(RegClass::V128, I128);
@@ -1752,12 +1738,11 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
rn, rn,
rm: tmp.to_reg(), rm: tmp.to_reg(),
}); });
ctx.emit(Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(8),
kind: CondBrKind::Cond(lower_fp_condcode(low_cond)),
});
let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow); let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow);
ctx.emit(Inst::Udf { trap_info }); ctx.emit(Inst::TrapIf {
trap_info,
kind: CondBrKind::Cond(lower_fp_condcode(low_cond).invert()),
});
// <= high_bound // <= high_bound
lower_constant_f32(ctx, tmp, high_bound); lower_constant_f32(ctx, tmp, high_bound);
@@ -1765,12 +1750,11 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
rn, rn,
rm: tmp.to_reg(), rm: tmp.to_reg(),
}); });
ctx.emit(Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(8),
kind: CondBrKind::Cond(lower_fp_condcode(FloatCC::LessThan)),
});
let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow); let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow);
ctx.emit(Inst::Udf { trap_info }); ctx.emit(Inst::TrapIf {
trap_info,
kind: CondBrKind::Cond(lower_fp_condcode(FloatCC::LessThan).invert()),
});
} else { } else {
// From float64. // From float64.
let (low_bound, low_cond, high_bound) = match (signed, out_bits) { let (low_bound, low_cond, high_bound) = match (signed, out_bits) {
@@ -1795,12 +1779,11 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
rn, rn,
rm: tmp.to_reg(), rm: tmp.to_reg(),
}); });
ctx.emit(Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(8),
kind: CondBrKind::Cond(lower_fp_condcode(low_cond)),
});
let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow); let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow);
ctx.emit(Inst::Udf { trap_info }); ctx.emit(Inst::TrapIf {
trap_info,
kind: CondBrKind::Cond(lower_fp_condcode(low_cond).invert()),
});
// <= high_bound // <= high_bound
lower_constant_f64(ctx, tmp, high_bound); lower_constant_f64(ctx, tmp, high_bound);
@@ -1808,12 +1791,11 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
rn, rn,
rm: tmp.to_reg(), rm: tmp.to_reg(),
}); });
ctx.emit(Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(8),
kind: CondBrKind::Cond(lower_fp_condcode(FloatCC::LessThan)),
});
let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow); let trap_info = (ctx.srcloc(insn), TrapCode::IntegerOverflow);
ctx.emit(Inst::Udf { trap_info }); ctx.emit(Inst::TrapIf {
trap_info,
kind: CondBrKind::Cond(lower_fp_condcode(FloatCC::LessThan).invert()),
});
}; };
// Do the conversion. // Do the conversion.
@@ -2307,7 +2289,8 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
let rtmp1 = ctx.alloc_tmp(RegClass::I64, I32); let rtmp1 = ctx.alloc_tmp(RegClass::I64, I32);
let rtmp2 = ctx.alloc_tmp(RegClass::I64, I32); let rtmp2 = ctx.alloc_tmp(RegClass::I64, I32);
// Bounds-check and branch to default. // Bounds-check, leaving condition codes for JTSequence's
// branch to default target below.
if let Some(imm12) = Imm12::maybe_from_u64(jt_size as u64) { if let Some(imm12) = Imm12::maybe_from_u64(jt_size as u64) {
ctx.emit(Inst::AluRRImm12 { ctx.emit(Inst::AluRRImm12 {
alu_op: ALUOp::SubS32, alu_op: ALUOp::SubS32,
@@ -2324,14 +2307,10 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
rm: rtmp1.to_reg(), rm: rtmp1.to_reg(),
}); });
} }
let default_target = BranchTarget::Label(targets[0]);
ctx.emit(Inst::OneWayCondBr {
target: default_target.clone(),
kind: CondBrKind::Cond(Cond::Hs), // unsigned >=
});
// Emit the compound instruction that does: // Emit the compound instruction that does:
// //
// b.hs default
// adr rA, jt // adr rA, jt
// ldrsw rB, [rA, rIndex, UXTW 2] // ldrsw rB, [rA, rIndex, UXTW 2]
// add rA, rA, rB // add rA, rA, rB
@@ -2350,6 +2329,7 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
.skip(1) .skip(1)
.map(|bix| BranchTarget::Label(*bix)) .map(|bix| BranchTarget::Label(*bix))
.collect(); .collect();
let default_target = BranchTarget::Label(targets[0]);
let targets_for_term: Vec<MachLabel> = targets.to_vec(); let targets_for_term: Vec<MachLabel> = targets.to_vec();
ctx.emit(Inst::JTSequence { ctx.emit(Inst::JTSequence {
ridx, ridx,
@@ -2357,6 +2337,7 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
rtmp2, rtmp2,
info: Box::new(JTSequenceInfo { info: Box::new(JTSequenceInfo {
targets: jt_targets, targets: jt_targets,
default_target,
targets_for_term: targets_for_term, targets_for_term: targets_for_term,
}), }),
}); });

View File

@@ -1390,7 +1390,9 @@ mod test {
inst.emit(&mut buf, &flags, &mut state); inst.emit(&mut buf, &flags, &mut state);
buf.bind_label(label(1)); buf.bind_label(label(1));
let inst = Inst::Nop4; let inst = Inst::Udf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
};
inst.emit(&mut buf, &flags, &mut state); inst.emit(&mut buf, &flags, &mut state);
buf.bind_label(label(2)); buf.bind_label(label(2));
@@ -1403,14 +1405,13 @@ mod test {
let mut buf2 = MachBuffer::new(); let mut buf2 = MachBuffer::new();
let mut state = Default::default(); let mut state = Default::default();
let inst = Inst::OneWayCondBr { let inst = Inst::TrapIf {
kind: CondBrKind::Zero(xreg(0)), kind: CondBrKind::NotZero(xreg(0)),
target: BranchTarget::ResolvedOffset(8), trap_info: (SourceLoc::default(), TrapCode::Interrupt),
}; };
inst.emit(&mut buf2, &flags, &mut state); inst.emit(&mut buf2, &flags, &mut state);
let inst = Inst::Nop4; let inst = Inst::Nop4;
inst.emit(&mut buf2, &flags, &mut state); inst.emit(&mut buf2, &flags, &mut state);
inst.emit(&mut buf2, &flags, &mut state);
let buf2 = buf2.finish(); let buf2 = buf2.finish();

View File

@@ -76,12 +76,10 @@ block0(v0: i64, v1: i64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: sdiv x2, x0, x1 ; nextln: sdiv x2, x0, x1
; nextln: cbz x1, 20 ; nextln: cbnz x1, 8 ; udf
; nextln: adds xzr, x1, #1 ; nextln: adds xzr, x1, #1
; nextln: ccmp x0, #1, #nzcv, eq ; nextln: ccmp x0, #1, #nzcv, eq
; nextln: b.vc 12 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: udf
; nextln: mov x0, x2 ; nextln: mov x0, x2
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -98,12 +96,10 @@ block0(v0: i64):
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: movz x2, #2 ; nextln: movz x2, #2
; nextln: sdiv x1, x0, x2 ; nextln: sdiv x1, x0, x2
; nextln: cbz x2, 20 ; nextln: cbnz x2, 8 ; udf
; nextln: adds xzr, x2, #1 ; nextln: adds xzr, x2, #1
; nextln: ccmp x0, #1, #nzcv, eq ; nextln: ccmp x0, #1, #nzcv, eq
; nextln: b.vc 12 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: udf
; nextln: mov x0, x1 ; nextln: mov x0, x1
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -118,8 +114,7 @@ block0(v0: i64, v1: i64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: udiv x0, x0, x1 ; nextln: udiv x0, x0, x1
; nextln: cbnz x1, 8 ; nextln: cbnz x1, 8 ; udf
; nextln: udf
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
; nextln: ret ; nextln: ret
@@ -135,8 +130,7 @@ block0(v0: i64):
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: movz x1, #2 ; nextln: movz x1, #2
; nextln: udiv x0, x0, x1 ; nextln: udiv x0, x0, x1
; nextln: cbnz x1, 8 ; nextln: cbnz x1, 8 ; udf
; nextln: udf
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
; nextln: ret ; nextln: ret
@@ -150,8 +144,7 @@ block0(v0: i64, v1: i64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: sdiv x2, x0, x1 ; nextln: sdiv x2, x0, x1
; nextln: cbnz x1, 8 ; nextln: cbnz x1, 8 ; udf
; nextln: udf
; nextln: msub x0, x2, x1, x0 ; nextln: msub x0, x2, x1, x0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -166,8 +159,7 @@ block0(v0: i64, v1: i64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: udiv x2, x0, x1 ; nextln: udiv x2, x0, x1
; nextln: cbnz x1, 8 ; nextln: cbnz x1, 8 ; udf
; nextln: udf
; nextln: msub x0, x2, x1, x0 ; nextln: msub x0, x2, x1, x0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -185,12 +177,10 @@ block0(v0: i32, v1: i32):
; nextln: sxtw x3, w0 ; nextln: sxtw x3, w0
; nextln: sxtw x2, w1 ; nextln: sxtw x2, w1
; nextln: sdiv x0, x3, x2 ; nextln: sdiv x0, x3, x2
; nextln: cbz x2, 20 ; nextln: cbnz x2, 8 ; udf
; nextln: adds wzr, w2, #1 ; nextln: adds wzr, w2, #1
; nextln: ccmp w3, #1, #nzcv, eq ; nextln: ccmp w3, #1, #nzcv, eq
; nextln: b.vc 12 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: udf
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
; nextln: ret ; nextln: ret
@@ -204,16 +194,15 @@ block0(v0: i32):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: sxtw x1, w0 ; nextln: sxtw x0, w0
; nextln: movz x0, #2 ; nextln: movz x1, #2
; nextln: sxtw x2, w0 ; nextln: sxtw x2, w1
; nextln: sdiv x0, x1, x2 ; nextln: sdiv x1, x0, x2
; nextln: cbz x2, 20 ; nextln: cbnz x2, 8 ; udf
; nextln: adds wzr, w2, #1 ; nextln: adds wzr, w2, #1
; nextln: ccmp w1, #1, #nzcv, eq ; nextln: ccmp w0, #1, #nzcv, eq
; nextln: b.vc 12 ; nextln: b.vc 8 ; udf
; nextln: udf ; nextln: mov x0, x1
; nextln: udf
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
; nextln: ret ; nextln: ret
@@ -229,8 +218,7 @@ block0(v0: i32, v1: i32):
; nextln: mov w0, w0 ; nextln: mov w0, w0
; nextln: mov w1, w1 ; nextln: mov w1, w1
; nextln: udiv x0, x0, x1 ; nextln: udiv x0, x0, x1
; nextln: cbnz x1, 8 ; nextln: cbnz x1, 8 ; udf
; nextln: udf
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
; nextln: ret ; nextln: ret
@@ -248,8 +236,7 @@ block0(v0: i32):
; nextln: mov w0, w0 ; nextln: mov w0, w0
; nextln: movz x1, #2 ; nextln: movz x1, #2
; nextln: udiv x0, x0, x1 ; nextln: udiv x0, x0, x1
; nextln: cbnz x1, 8 ; nextln: cbnz x1, 8 ; udf
; nextln: udf
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
; nextln: ret ; nextln: ret
@@ -265,8 +252,7 @@ block0(v0: i32, v1: i32):
; nextln: sxtw x0, w0 ; nextln: sxtw x0, w0
; nextln: sxtw x1, w1 ; nextln: sxtw x1, w1
; nextln: sdiv x2, x0, x1 ; nextln: sdiv x2, x0, x1
; nextln: cbnz x1, 8 ; nextln: cbnz x1, 8 ; udf
; nextln: udf
; nextln: msub x0, x2, x1, x0 ; nextln: msub x0, x2, x1, x0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -283,8 +269,7 @@ block0(v0: i32, v1: i32):
; nextln: mov w0, w0 ; nextln: mov w0, w0
; nextln: mov w1, w1 ; nextln: mov w1, w1
; nextln: udiv x2, x0, x1 ; nextln: udiv x2, x0, x1
; nextln: cbnz x1, 8 ; nextln: cbnz x1, 8 ; udf
; nextln: udf
; nextln: msub x0, x2, x1, x0 ; nextln: msub x0, x2, x1, x0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16

View File

@@ -426,16 +426,13 @@ block0(v0: f32):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: fcmp s0, s0 ; nextln: fcmp s0, s0
; nextln: b.vc 8 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: ldr s1, pc+8 ; b 8 ; data.f32 -1 ; nextln: ldr s1, pc+8 ; b 8 ; data.f32 -1
; nextln: fcmp s0, s1 ; nextln: fcmp s0, s1
; nextln: b.gt 8 ; nextln: b.gt 8 ; udf
; nextln: udf
; nextln: ldr s1, pc+8 ; b 8 ; data.f32 4294967300 ; nextln: ldr s1, pc+8 ; b 8 ; data.f32 4294967300
; nextln: fcmp s0, s1 ; nextln: fcmp s0, s1
; nextln: b.mi 8 ; nextln: b.mi 8 ; udf
; nextln: udf
; nextln: fcvtzu w0, s0 ; nextln: fcvtzu w0, s0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -450,16 +447,13 @@ block0(v0: f32):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: fcmp s0, s0 ; nextln: fcmp s0, s0
; nextln: b.vc 8 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: ldr s1, pc+8 ; b 8 ; data.f32 -2147483600 ; nextln: ldr s1, pc+8 ; b 8 ; data.f32 -2147483600
; nextln: fcmp s0, s1 ; nextln: fcmp s0, s1
; nextln: b.ge 8 ; nextln: b.ge 8 ; udf
; nextln: udf
; nextln: ldr s1, pc+8 ; b 8 ; data.f32 2147483600 ; nextln: ldr s1, pc+8 ; b 8 ; data.f32 2147483600
; nextln: fcmp s0, s1 ; nextln: fcmp s0, s1
; nextln: b.mi ; nextln: b.mi 8 ; udf
; nextln: udf
; nextln: fcvtzs w0, s0 ; nextln: fcvtzs w0, s0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -474,16 +468,13 @@ block0(v0: f32):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: fcmp s0, s0 ; nextln: fcmp s0, s0
; nextln: b.vc 8 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: ldr s1, pc+8 ; b 8 ; data.f32 -1 ; nextln: ldr s1, pc+8 ; b 8 ; data.f32 -1
; nextln: fcmp s0, s1 ; nextln: fcmp s0, s1
; nextln: b.gt 8 ; nextln: b.gt 8 ; udf
; nextln: udf
; nextln: ldr s1, pc+8 ; b 8 ; data.f32 18446744000000000000 ; nextln: ldr s1, pc+8 ; b 8 ; data.f32 18446744000000000000
; nextln: fcmp s0, s1 ; nextln: fcmp s0, s1
; nextln: b.mi 8 ; nextln: b.mi 8 ; udf
; nextln: udf
; nextln: fcvtzu x0, s0 ; nextln: fcvtzu x0, s0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -498,16 +489,13 @@ block0(v0: f32):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: fcmp s0, s0 ; nextln: fcmp s0, s0
; nextln: b.vc 8 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: ldr s1, pc+8 ; b 8 ; data.f32 -9223372000000000000 ; nextln: ldr s1, pc+8 ; b 8 ; data.f32 -9223372000000000000
; nextln: fcmp s0, s1 ; nextln: fcmp s0, s1
; nextln: b.ge 8 ; nextln: b.ge 8 ; udf
; nextln: udf
; nextln: ldr s1, pc+8 ; b 8 ; data.f32 9223372000000000000 ; nextln: ldr s1, pc+8 ; b 8 ; data.f32 9223372000000000000
; nextln: fcmp s0, s1 ; nextln: fcmp s0, s1
; nextln: b.mi 8 ; nextln: b.mi 8 ; udf
; nextln: udf
; nextln: fcvtzs x0, s0 ; nextln: fcvtzs x0, s0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -522,16 +510,13 @@ block0(v0: f64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: fcmp d0, d0 ; nextln: fcmp d0, d0
; nextln: b.vc 8 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 -1 ; nextln: ldr d1, pc+8 ; b 12 ; data.f64 -1
; nextln: fcmp d0, d1 ; nextln: fcmp d0, d1
; nextln: b.gt 8 ; nextln: b.gt 8 ; udf
; nextln: udf
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 4294967296 ; nextln: ldr d1, pc+8 ; b 12 ; data.f64 4294967296
; nextln: fcmp d0, d1 ; nextln: fcmp d0, d1
; nextln: b.mi 8 ; nextln: b.mi 8 ; udf
; nextln: udf
; nextln: fcvtzu w0, d0 ; nextln: fcvtzu w0, d0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -546,16 +531,13 @@ block0(v0: f64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: fcmp d0, d0 ; nextln: fcmp d0, d0
; nextln: b.vc 8 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 -2147483649 ; nextln: ldr d1, pc+8 ; b 12 ; data.f64 -2147483649
; nextln: fcmp d0, d1 ; nextln: fcmp d0, d1
; nextln: b.gt 8 ; nextln: b.gt 8 ; udf
; nextln: udf
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 2147483648 ; nextln: ldr d1, pc+8 ; b 12 ; data.f64 2147483648
; nextln: fcmp d0, d1 ; nextln: fcmp d0, d1
; nextln: b.mi 8 ; nextln: b.mi 8 ; udf
; nextln: udf
; nextln: fcvtzs w0, d0 ; nextln: fcvtzs w0, d0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -570,16 +552,13 @@ block0(v0: f64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: fcmp d0, d0 ; nextln: fcmp d0, d0
; nextln: b.vc 8 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 -1 ; nextln: ldr d1, pc+8 ; b 12 ; data.f64 -1
; nextln: fcmp d0, d1 ; nextln: fcmp d0, d1
; nextln: b.gt 8 ; nextln: b.gt 8 ; udf
; nextln: udf
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 18446744073709552000 ; nextln: ldr d1, pc+8 ; b 12 ; data.f64 18446744073709552000
; nextln: fcmp d0, d1 ; nextln: fcmp d0, d1
; nextln: b.mi 8 ; nextln: b.mi 8 ; udf
; nextln: udf
; nextln: fcvtzu x0, d0 ; nextln: fcvtzu x0, d0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -594,16 +573,13 @@ block0(v0: f64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: fcmp d0, d0 ; nextln: fcmp d0, d0
; nextln: b.vc 8 ; nextln: b.vc 8 ; udf
; nextln: udf
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 -9223372036854776000 ; nextln: ldr d1, pc+8 ; b 12 ; data.f64 -9223372036854776000
; nextln: fcmp d0, d1 ; nextln: fcmp d0, d1
; nextln: b.ge 8 ; nextln: b.ge 8 ; udf
; nextln: udf
; nextln: ldr d1, pc+8 ; b 12 ; data.f64 9223372036854776000 ; nextln: ldr d1, pc+8 ; b 12 ; data.f64 9223372036854776000
; nextln: fcmp d0, d1 ; nextln: fcmp d0, d1
; nextln: b.mi 8 ; nextln: b.mi 8 ; udf
; nextln: udf
; nextln: fcvtzs x0, d0 ; nextln: fcvtzs x0, d0
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16

View File

@@ -29,8 +29,7 @@ block5(v5: i64):
} }
; check: subs wzr, w0, #3 ; check: subs wzr, w0, #3
; nextln: b.hs ; nextln: b.hs label1 ; adr x1, pc+16 ; ldrsw x2, [x1, x0, LSL 2] ; add x1, x1, x2 ; br x1 ; jt_entries
; nextln: adr x1, pc+16 ; ldrsw x2, [x1, x0, LSL 2] ; add x1, x1, x2 ; br x1 ; jt_entries
; check: movz x1, #1 ; check: movz x1, #1
; nextln: b ; nextln: b

View File

@@ -43,8 +43,7 @@ block0(v0: i64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: subs xzr, sp, x0 ; nextln: subs xzr, sp, x0
; nextln: b.hs 8 ; nextln: b.hs 8 ; udf
; nextln: udf
; nextln: ldr x16 ; nextln: ldr x16
; nextln: blr x16 ; nextln: blr x16
; nextln: mov sp, fp ; nextln: mov sp, fp
@@ -67,8 +66,7 @@ block0(v0: i64):
; nextln: ldur x16, [x0] ; nextln: ldur x16, [x0]
; nextln: ldur x16, [x16, #4] ; nextln: ldur x16, [x16, #4]
; nextln: subs xzr, sp, x16 ; nextln: subs xzr, sp, x16
; nextln: b.hs 8 ; nextln: b.hs 8 ; udf
; nextln: udf
; nextln: ldr x16 ; nextln: ldr x16
; nextln: blr x16 ; nextln: blr x16
; nextln: mov sp, fp ; nextln: mov sp, fp
@@ -86,8 +84,7 @@ block0(v0: i64):
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: add x16, x0, #176 ; nextln: add x16, x0, #176
; nextln: subs xzr, sp, x16 ; nextln: subs xzr, sp, x16
; nextln: b.hs 8 ; nextln: b.hs 8 ; udf
; nextln: udf
; nextln: sub sp, sp, #176 ; nextln: sub sp, sp, #176
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -102,14 +99,12 @@ block0(v0: i64):
; check: stp fp, lr, [sp, #-16]! ; check: stp fp, lr, [sp, #-16]!
; nextln: mov fp, sp ; nextln: mov fp, sp
; nextln: subs xzr, sp, x0 ; nextln: subs xzr, sp, x0
; nextln: b.hs 8 ; nextln: b.hs 8 ; udf
; nextln: udf
; nextln: movz x17, #6784 ; nextln: movz x17, #6784
; nextln: movk x17, #6, LSL #16 ; nextln: movk x17, #6, LSL #16
; nextln: add x16, x0, x17, UXTX ; nextln: add x16, x0, x17, UXTX
; nextln: subs xzr, sp, x16 ; nextln: subs xzr, sp, x16
; nextln: b.hs 8 ; nextln: b.hs 8 ; udf
; nextln: udf
; nextln: ldr x16, 8 ; b 12 ; data 400000 ; nextln: ldr x16, 8 ; b 12 ; data 400000
; nextln: sub sp, sp, x16, UXTX ; nextln: sub sp, sp, x16, UXTX
; nextln: mov sp, fp ; nextln: mov sp, fp
@@ -132,8 +127,7 @@ block0(v0: i64):
; nextln: ldur x16, [x16, #4] ; nextln: ldur x16, [x16, #4]
; nextln: add x16, x16, #32 ; nextln: add x16, x16, #32
; nextln: subs xzr, sp, x16 ; nextln: subs xzr, sp, x16
; nextln: b.hs 8 ; nextln: b.hs 8 ; udf
; nextln: udf
; nextln: sub sp, sp, #32 ; nextln: sub sp, sp, #32
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16
@@ -154,14 +148,12 @@ block0(v0: i64):
; nextln: ldur x16, [x0] ; nextln: ldur x16, [x0]
; nextln: ldur x16, [x16, #4] ; nextln: ldur x16, [x16, #4]
; nextln: subs xzr, sp, x16 ; nextln: subs xzr, sp, x16
; nextln: b.hs 8 ; nextln: b.hs 8 ; udf
; nextln: udf
; nextln: movz x17, #6784 ; nextln: movz x17, #6784
; nextln: movk x17, #6, LSL #16 ; nextln: movk x17, #6, LSL #16
; nextln: add x16, x16, x17, UXTX ; nextln: add x16, x16, x17, UXTX
; nextln: subs xzr, sp, x16 ; nextln: subs xzr, sp, x16
; nextln: b.hs 8 ; nextln: b.hs 8 ; udf
; nextln: udf
; nextln: ldr x16, 8 ; b 12 ; data 400000 ; nextln: ldr x16, 8 ; b 12 ; data 400000
; nextln: sub sp, sp, x16, UXTX ; nextln: sub sp, sp, x16, UXTX
; nextln: mov sp, fp ; nextln: mov sp, fp
@@ -182,8 +174,7 @@ block0(v0: i64):
; nextln: movz x16, #6784 ; movk x16, #6, LSL #16 ; add x16, x0, x16, UXTX ; ldr x16, [x16] ; nextln: movz x16, #6784 ; movk x16, #6, LSL #16 ; add x16, x0, x16, UXTX ; ldr x16, [x16]
; nextln: add x16, x16, #32 ; nextln: add x16, x16, #32
; nextln: subs xzr, sp, x16 ; nextln: subs xzr, sp, x16
; nextln: b.hs 8 ; nextln: b.hs 8 ; udf
; nextln: udf
; nextln: sub sp, sp, #32 ; nextln: sub sp, sp, #32
; nextln: mov sp, fp ; nextln: mov sp, fp
; nextln: ldp fp, lr, [sp], #16 ; nextln: ldp fp, lr, [sp], #16

View File

@@ -17,8 +17,7 @@ block0(v0: i64):
} }
; check: subs xzr, x0, #42 ; check: subs xzr, x0, #42
; nextln: b.ne 8 ; nextln: b.ne 8 ; udf
; nextln: udf
function %h() { function %h() {
block0: block0: