Review fixes;
This commit is contained in:
@@ -122,27 +122,6 @@ impl IntCC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines whether this condcode interprets inputs as signed or
|
|
||||||
/// unsigned. See the documentation for the `icmp` instruction in
|
|
||||||
/// cranelift-codegen/meta/src/shared/instructions.rs for further insights
|
|
||||||
/// into this.
|
|
||||||
pub fn is_signed(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
IntCC::Equal
|
|
||||||
| IntCC::UnsignedGreaterThanOrEqual
|
|
||||||
| IntCC::UnsignedGreaterThan
|
|
||||||
| IntCC::UnsignedLessThanOrEqual
|
|
||||||
| IntCC::UnsignedLessThan
|
|
||||||
| IntCC::NotEqual => false,
|
|
||||||
IntCC::SignedGreaterThanOrEqual
|
|
||||||
| IntCC::SignedGreaterThan
|
|
||||||
| IntCC::SignedLessThanOrEqual
|
|
||||||
| IntCC::SignedLessThan
|
|
||||||
| IntCC::Overflow
|
|
||||||
| IntCC::NotOverflow => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the corresponding string condition code for the IntCC object.
|
/// Get the corresponding string condition code for the IntCC object.
|
||||||
pub fn to_static_str(self) -> &'static str {
|
pub fn to_static_str(self) -> &'static str {
|
||||||
use self::IntCC::*;
|
use self::IntCC::*;
|
||||||
|
|||||||
@@ -1501,7 +1501,7 @@ impl MachInstEmit for Inst {
|
|||||||
}
|
}
|
||||||
&Inst::Call { ref info } => {
|
&Inst::Call { ref info } => {
|
||||||
if let Some(s) = state.take_stackmap() {
|
if let Some(s) = state.take_stackmap() {
|
||||||
sink.add_stackmap(4, s);
|
sink.add_stackmap(StackmapExtent::UpcomingBytes(4), s);
|
||||||
}
|
}
|
||||||
sink.add_reloc(info.loc, Reloc::Arm64Call, &info.dest, 0);
|
sink.add_reloc(info.loc, Reloc::Arm64Call, &info.dest, 0);
|
||||||
sink.put4(enc_jump26(0b100101, 0));
|
sink.put4(enc_jump26(0b100101, 0));
|
||||||
@@ -1511,7 +1511,7 @@ impl MachInstEmit for Inst {
|
|||||||
}
|
}
|
||||||
&Inst::CallInd { ref info } => {
|
&Inst::CallInd { ref info } => {
|
||||||
if let Some(s) = state.take_stackmap() {
|
if let Some(s) = state.take_stackmap() {
|
||||||
sink.add_stackmap(4, s);
|
sink.add_stackmap(StackmapExtent::UpcomingBytes(4), s);
|
||||||
}
|
}
|
||||||
sink.put4(0b1101011_0001_11111_000000_00000_00000 | (machreg_to_gpr(info.rn) << 5));
|
sink.put4(0b1101011_0001_11111_000000_00000_00000 | (machreg_to_gpr(info.rn) << 5));
|
||||||
if info.opcode.is_call() {
|
if info.opcode.is_call() {
|
||||||
@@ -1569,7 +1569,7 @@ impl MachInstEmit for Inst {
|
|||||||
let (srcloc, code) = trap_info;
|
let (srcloc, code) = trap_info;
|
||||||
sink.add_trap(srcloc, code);
|
sink.add_trap(srcloc, code);
|
||||||
if let Some(s) = state.take_stackmap() {
|
if let Some(s) = state.take_stackmap() {
|
||||||
sink.add_stackmap(4, s);
|
sink.add_stackmap(StackmapExtent::UpcomingBytes(4), s);
|
||||||
}
|
}
|
||||||
sink.put4(0xd4a00000);
|
sink.put4(0xd4a00000);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -798,6 +798,26 @@ pub(crate) fn lower_vector_compare<C: LowerCtx<I = Inst>>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines whether this condcode interprets inputs as signed or unsigned. See the
|
||||||
|
/// documentation for the `icmp` instruction in cranelift-codegen/meta/src/shared/instructions.rs
|
||||||
|
/// for further insights into this.
|
||||||
|
pub(crate) fn condcode_is_signed(cc: IntCC) -> bool {
|
||||||
|
match cc {
|
||||||
|
IntCC::Equal
|
||||||
|
| IntCC::UnsignedGreaterThanOrEqual
|
||||||
|
| IntCC::UnsignedGreaterThan
|
||||||
|
| IntCC::UnsignedLessThanOrEqual
|
||||||
|
| IntCC::UnsignedLessThan
|
||||||
|
| IntCC::NotEqual => false,
|
||||||
|
IntCC::SignedGreaterThanOrEqual
|
||||||
|
| IntCC::SignedGreaterThan
|
||||||
|
| IntCC::SignedLessThanOrEqual
|
||||||
|
| IntCC::SignedLessThan
|
||||||
|
| IntCC::Overflow
|
||||||
|
| IntCC::NotOverflow => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Helpers for instruction lowering.
|
// Helpers for instruction lowering.
|
||||||
|
|
||||||
|
|||||||
@@ -1115,7 +1115,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
{
|
{
|
||||||
let condcode = inst_condcode(ctx.data(icmp_insn)).unwrap();
|
let condcode = inst_condcode(ctx.data(icmp_insn)).unwrap();
|
||||||
let cond = lower_condcode(condcode);
|
let cond = lower_condcode(condcode);
|
||||||
let is_signed = condcode.is_signed();
|
let is_signed = condcode_is_signed(condcode);
|
||||||
lower_icmp_or_ifcmp_to_flags(ctx, icmp_insn, is_signed);
|
lower_icmp_or_ifcmp_to_flags(ctx, icmp_insn, is_signed);
|
||||||
cond
|
cond
|
||||||
} else if let Some(fcmp_insn) =
|
} else if let Some(fcmp_insn) =
|
||||||
@@ -1161,7 +1161,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
Opcode::Selectif | Opcode::SelectifSpectreGuard => {
|
Opcode::Selectif | Opcode::SelectifSpectreGuard => {
|
||||||
let condcode = inst_condcode(ctx.data(insn)).unwrap();
|
let condcode = inst_condcode(ctx.data(insn)).unwrap();
|
||||||
let cond = lower_condcode(condcode);
|
let cond = lower_condcode(condcode);
|
||||||
let is_signed = condcode.is_signed();
|
let is_signed = condcode_is_signed(condcode);
|
||||||
// Verification ensures that the input is always a
|
// Verification ensures that the input is always a
|
||||||
// single-def ifcmp.
|
// single-def ifcmp.
|
||||||
let ifcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ifcmp).unwrap();
|
let ifcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ifcmp).unwrap();
|
||||||
@@ -1232,7 +1232,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
Opcode::Trueif => {
|
Opcode::Trueif => {
|
||||||
let condcode = inst_condcode(ctx.data(insn)).unwrap();
|
let condcode = inst_condcode(ctx.data(insn)).unwrap();
|
||||||
let cond = lower_condcode(condcode);
|
let cond = lower_condcode(condcode);
|
||||||
let is_signed = condcode.is_signed();
|
let is_signed = condcode_is_signed(condcode);
|
||||||
// Verification ensures that the input is always a
|
// Verification ensures that the input is always a
|
||||||
// single-def ifcmp.
|
// single-def ifcmp.
|
||||||
let ifcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ifcmp).unwrap();
|
let ifcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ifcmp).unwrap();
|
||||||
@@ -1433,7 +1433,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
Opcode::Icmp => {
|
Opcode::Icmp => {
|
||||||
let condcode = inst_condcode(ctx.data(insn)).unwrap();
|
let condcode = inst_condcode(ctx.data(insn)).unwrap();
|
||||||
let cond = lower_condcode(condcode);
|
let cond = lower_condcode(condcode);
|
||||||
let is_signed = condcode.is_signed();
|
let is_signed = condcode_is_signed(condcode);
|
||||||
let rd = get_output_reg(ctx, outputs[0]);
|
let rd = get_output_reg(ctx, outputs[0]);
|
||||||
let ty = ctx.input_ty(insn, 0);
|
let ty = ctx.input_ty(insn, 0);
|
||||||
let bits = ty_bits(ty);
|
let bits = ty_bits(ty);
|
||||||
@@ -1509,7 +1509,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
} else if op == Opcode::Trapif {
|
} else if op == Opcode::Trapif {
|
||||||
let condcode = inst_condcode(ctx.data(insn)).unwrap();
|
let condcode = inst_condcode(ctx.data(insn)).unwrap();
|
||||||
let cond = lower_condcode(condcode);
|
let cond = lower_condcode(condcode);
|
||||||
let is_signed = condcode.is_signed();
|
let is_signed = condcode_is_signed(condcode);
|
||||||
|
|
||||||
// Verification ensures that the input is always a single-def ifcmp.
|
// Verification ensures that the input is always a single-def ifcmp.
|
||||||
let ifcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ifcmp).unwrap();
|
let ifcmp_insn = maybe_input_insn(ctx, inputs[0], Opcode::Ifcmp).unwrap();
|
||||||
@@ -2360,7 +2360,7 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
|
|||||||
{
|
{
|
||||||
let condcode = inst_condcode(ctx.data(icmp_insn)).unwrap();
|
let condcode = inst_condcode(ctx.data(icmp_insn)).unwrap();
|
||||||
let cond = lower_condcode(condcode);
|
let cond = lower_condcode(condcode);
|
||||||
let is_signed = condcode.is_signed();
|
let is_signed = condcode_is_signed(condcode);
|
||||||
let negated = op0 == Opcode::Brz;
|
let negated = op0 == Opcode::Brz;
|
||||||
let cond = if negated { cond.invert() } else { cond };
|
let cond = if negated { cond.invert() } else { cond };
|
||||||
|
|
||||||
@@ -2410,7 +2410,7 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
|
|||||||
let cond = lower_condcode(condcode);
|
let cond = lower_condcode(condcode);
|
||||||
let kind = CondBrKind::Cond(cond);
|
let kind = CondBrKind::Cond(cond);
|
||||||
|
|
||||||
let is_signed = condcode.is_signed();
|
let is_signed = condcode_is_signed(condcode);
|
||||||
let ty = ctx.input_ty(branches[0], 0);
|
let ty = ctx.input_ty(branches[0], 0);
|
||||||
let bits = ty_bits(ty);
|
let bits = ty_bits(ty);
|
||||||
let narrow_mode = match (bits <= 32, is_signed) {
|
let narrow_mode = match (bits <= 32, is_signed) {
|
||||||
@@ -2451,7 +2451,7 @@ pub(crate) fn lower_branch<C: LowerCtx<I = Inst>>(
|
|||||||
let cond = lower_condcode(condcode);
|
let cond = lower_condcode(condcode);
|
||||||
let kind = CondBrKind::Cond(cond);
|
let kind = CondBrKind::Cond(cond);
|
||||||
|
|
||||||
let is_signed = condcode.is_signed();
|
let is_signed = condcode_is_signed(condcode);
|
||||||
let flag_input = InsnInput {
|
let flag_input = InsnInput {
|
||||||
insn: branches[0],
|
insn: branches[0],
|
||||||
input: 0,
|
input: 0,
|
||||||
|
|||||||
@@ -373,6 +373,26 @@ fn emit_simm(sink: &mut MachBuffer<Inst>, size: u8, simm32: u32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A small helper to generate a signed conversion instruction.
|
||||||
|
fn emit_signed_cvt(
|
||||||
|
sink: &mut MachBuffer<Inst>,
|
||||||
|
flags: &settings::Flags,
|
||||||
|
state: &mut EmitState,
|
||||||
|
src: Reg,
|
||||||
|
dst: Writable<Reg>,
|
||||||
|
to_f64: bool,
|
||||||
|
) {
|
||||||
|
// Handle an unsigned int, which is the "easy" case: a signed conversion will do the
|
||||||
|
// right thing.
|
||||||
|
let op = if to_f64 {
|
||||||
|
SseOpcode::Cvtsi2sd
|
||||||
|
} else {
|
||||||
|
SseOpcode::Cvtsi2ss
|
||||||
|
};
|
||||||
|
let inst = Inst::gpr_to_xmm(op, RegMem::reg(src), OperandSize::Size64, dst);
|
||||||
|
inst.emit(sink, flags, state);
|
||||||
|
}
|
||||||
|
|
||||||
/// Emits a one way conditional jump if CC is set (true).
|
/// Emits a one way conditional jump if CC is set (true).
|
||||||
fn one_way_jmp(sink: &mut MachBuffer<Inst>, cc: CC, label: MachLabel) {
|
fn one_way_jmp(sink: &mut MachBuffer<Inst>, cc: CC, label: MachLabel) {
|
||||||
let cond_start = sink.cur_offset();
|
let cond_start = sink.cur_offset();
|
||||||
@@ -700,7 +720,7 @@ pub(crate) fn emit(
|
|||||||
debug_assert!(flags.avoid_div_traps());
|
debug_assert!(flags.avoid_div_traps());
|
||||||
|
|
||||||
// Check if the divisor is zero, first.
|
// Check if the divisor is zero, first.
|
||||||
let inst = Inst::cmp_rmi_r(*size, RegMemImm::imm(0), *divisor);
|
let inst = Inst::cmp_rmi_r(*size, RegMemImm::imm(0), divisor.to_reg());
|
||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
|
|
||||||
let inst = Inst::trap_if(CC::Z, TrapCode::IntegerDivisionByZero, *loc);
|
let inst = Inst::trap_if(CC::Z, TrapCode::IntegerDivisionByZero, *loc);
|
||||||
@@ -708,7 +728,7 @@ pub(crate) fn emit(
|
|||||||
|
|
||||||
let (do_op, done_label) = if kind.is_signed() {
|
let (do_op, done_label) = if kind.is_signed() {
|
||||||
// Now check if the divisor is -1.
|
// Now check if the divisor is -1.
|
||||||
let inst = Inst::cmp_rmi_r(*size, RegMemImm::imm(0xffffffff), *divisor);
|
let inst = Inst::cmp_rmi_r(*size, RegMemImm::imm(0xffffffff), divisor.to_reg());
|
||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
|
|
||||||
let do_op = sink.get_label();
|
let do_op = sink.get_label();
|
||||||
@@ -768,7 +788,7 @@ pub(crate) fn emit(
|
|||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
let inst = Inst::div(*size, kind.is_signed(), RegMem::reg(*divisor), *loc);
|
let inst = Inst::div(*size, kind.is_signed(), RegMem::reg(divisor.to_reg()), *loc);
|
||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
|
|
||||||
// Lowering takes care of moving the result back into the right register, see comment
|
// Lowering takes care of moving the result back into the right register, see comment
|
||||||
@@ -1283,7 +1303,7 @@ pub(crate) fn emit(
|
|||||||
dest, loc, opcode, ..
|
dest, loc, opcode, ..
|
||||||
} => {
|
} => {
|
||||||
if let Some(s) = state.take_stackmap() {
|
if let Some(s) = state.take_stackmap() {
|
||||||
sink.add_stackmap(5, s);
|
sink.add_stackmap(StackmapExtent::UpcomingBytes(5), s);
|
||||||
}
|
}
|
||||||
sink.put1(0xE8);
|
sink.put1(0xE8);
|
||||||
// The addend adjusts for the difference between the end of the instruction and the
|
// The addend adjusts for the difference between the end of the instruction and the
|
||||||
@@ -1327,7 +1347,7 @@ pub(crate) fn emit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(s) = state.take_stackmap() {
|
if let Some(s) = state.take_stackmap() {
|
||||||
sink.add_stackmap_ending_at(start_offset, s);
|
sink.add_stackmap(StackmapExtent::StartedAtOffset(start_offset), s);
|
||||||
}
|
}
|
||||||
if opcode.is_call() {
|
if opcode.is_call() {
|
||||||
sink.add_call_site(*loc, *opcode);
|
sink.add_call_site(*loc, *opcode);
|
||||||
@@ -1611,13 +1631,13 @@ pub(crate) fn emit(
|
|||||||
// j done
|
// j done
|
||||||
//
|
//
|
||||||
// ;; to get the desired NaN behavior (signalling NaN transformed into a quiet NaN, the
|
// ;; to get the desired NaN behavior (signalling NaN transformed into a quiet NaN, the
|
||||||
// NaN value is returned), we add both inputs.
|
// ;; NaN value is returned), we add both inputs.
|
||||||
// propagate_nan:
|
// propagate_nan:
|
||||||
// add{ss,sd} %lhs, %rhs_dst
|
// add{ss,sd} %lhs, %rhs_dst
|
||||||
// j done
|
// j done
|
||||||
//
|
//
|
||||||
// do_min_max:
|
// do_min_max:
|
||||||
// min{ss,sd} %lhs, %rhs_dst
|
// {min,max}{ss,sd} %lhs, %rhs_dst
|
||||||
//
|
//
|
||||||
// done:
|
// done:
|
||||||
let done = sink.get_label();
|
let done = sink.get_label();
|
||||||
@@ -1707,8 +1727,9 @@ pub(crate) fn emit(
|
|||||||
dst_size,
|
dst_size,
|
||||||
} => {
|
} => {
|
||||||
let (prefix, opcode, dst_first) = match op {
|
let (prefix, opcode, dst_first) = match op {
|
||||||
SseOpcode::Movd => (LegacyPrefix::_66, 0x0F7E, false),
|
// Movd and movq use the same opcode; the presence of the REX prefix (set below)
|
||||||
SseOpcode::Movq => (LegacyPrefix::_66, 0x0F7E, false),
|
// actually determines which is used.
|
||||||
|
SseOpcode::Movd | SseOpcode::Movq => (LegacyPrefix::_66, 0x0F7E, false),
|
||||||
SseOpcode::Cvttss2si => (LegacyPrefix::_F3, 0x0F2C, true),
|
SseOpcode::Cvttss2si => (LegacyPrefix::_F3, 0x0F2C, true),
|
||||||
SseOpcode::Cvttsd2si => (LegacyPrefix::_F2, 0x0F2C, true),
|
SseOpcode::Cvttsd2si => (LegacyPrefix::_F2, 0x0F2C, true),
|
||||||
_ => panic!("unexpected opcode {:?}", op),
|
_ => panic!("unexpected opcode {:?}", op),
|
||||||
@@ -1734,8 +1755,9 @@ pub(crate) fn emit(
|
|||||||
src_size,
|
src_size,
|
||||||
} => {
|
} => {
|
||||||
let (prefix, opcode) = match op {
|
let (prefix, opcode) = match op {
|
||||||
SseOpcode::Movd => (LegacyPrefix::_66, 0x0F6E),
|
// Movd and movq use the same opcode; the presence of the REX prefix (set below)
|
||||||
SseOpcode::Movq => (LegacyPrefix::_66, 0x0F6E),
|
// actually determines which is used.
|
||||||
|
SseOpcode::Movd | SseOpcode::Movq => (LegacyPrefix::_66, 0x0F6E),
|
||||||
SseOpcode::Cvtsi2ss => (LegacyPrefix::_F3, 0x0F2A),
|
SseOpcode::Cvtsi2ss => (LegacyPrefix::_F3, 0x0F2A),
|
||||||
SseOpcode::Cvtsi2sd => (LegacyPrefix::_F2, 0x0F2A),
|
SseOpcode::Cvtsi2sd => (LegacyPrefix::_F2, 0x0F2A),
|
||||||
_ => panic!("unexpected opcode {:?}", op),
|
_ => panic!("unexpected opcode {:?}", op),
|
||||||
@@ -1781,6 +1803,9 @@ pub(crate) fn emit(
|
|||||||
tmp_gpr1,
|
tmp_gpr1,
|
||||||
tmp_gpr2,
|
tmp_gpr2,
|
||||||
} => {
|
} => {
|
||||||
|
// Note: this sequence is specific to 64-bit mode; a 32-bit mode would require a
|
||||||
|
// different sequence.
|
||||||
|
//
|
||||||
// Emit the following sequence:
|
// Emit the following sequence:
|
||||||
//
|
//
|
||||||
// cmp 0, %src
|
// cmp 0, %src
|
||||||
@@ -1790,6 +1815,7 @@ pub(crate) fn emit(
|
|||||||
// cvtsi2sd/cvtsi2ss %src, %dst
|
// cvtsi2sd/cvtsi2ss %src, %dst
|
||||||
// j done
|
// j done
|
||||||
//
|
//
|
||||||
|
// ;; handle negative: see below for an explanation of what it's doing.
|
||||||
// handle_negative:
|
// handle_negative:
|
||||||
// mov %src, %tmp_gpr1
|
// mov %src, %tmp_gpr1
|
||||||
// shr $1, %tmp_gpr1
|
// shr $1, %tmp_gpr1
|
||||||
@@ -1801,39 +1827,24 @@ pub(crate) fn emit(
|
|||||||
//
|
//
|
||||||
// done:
|
// done:
|
||||||
|
|
||||||
// A small helper to generate a signed conversion instruction, that helps deduplicating
|
assert!(src != tmp_gpr1);
|
||||||
// code below.
|
assert!(src != tmp_gpr2);
|
||||||
let emit_signed_cvt = |sink: &mut MachBuffer<Inst>,
|
assert!(tmp_gpr1 != tmp_gpr2);
|
||||||
flags: &settings::Flags,
|
|
||||||
state: &mut EmitState,
|
|
||||||
src: Reg,
|
|
||||||
dst: Writable<Reg>,
|
|
||||||
to_f64: bool| {
|
|
||||||
// Handle an unsigned int, which is the "easy" case: a signed conversion will do the
|
|
||||||
// right thing.
|
|
||||||
let op = if to_f64 {
|
|
||||||
SseOpcode::Cvtsi2sd
|
|
||||||
} else {
|
|
||||||
SseOpcode::Cvtsi2ss
|
|
||||||
};
|
|
||||||
let inst = Inst::gpr_to_xmm(op, RegMem::reg(src), OperandSize::Size64, dst);
|
|
||||||
inst.emit(sink, flags, state);
|
|
||||||
};
|
|
||||||
|
|
||||||
let handle_negative = sink.get_label();
|
let handle_negative = sink.get_label();
|
||||||
let done = sink.get_label();
|
let done = sink.get_label();
|
||||||
|
|
||||||
// If x seen as a signed int is not negative, a signed-conversion will do the right
|
// If x seen as a signed int64 is not negative, a signed-conversion will do the right
|
||||||
// thing.
|
// thing.
|
||||||
// TODO use tst src, src here.
|
// TODO use tst src, src here.
|
||||||
let inst = Inst::cmp_rmi_r(8, RegMemImm::imm(0), *src);
|
let inst = Inst::cmp_rmi_r(8, RegMemImm::imm(0), src.to_reg());
|
||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
|
|
||||||
one_way_jmp(sink, CC::L, handle_negative);
|
one_way_jmp(sink, CC::L, handle_negative);
|
||||||
|
|
||||||
// Handle an unsigned int, which is the "easy" case: a signed conversion will do the
|
// Handle a positive int64, which is the "easy" case: a signed conversion will do the
|
||||||
// right thing.
|
// right thing.
|
||||||
emit_signed_cvt(sink, flags, state, *src, *dst, *to_f64);
|
emit_signed_cvt(sink, flags, state, src.to_reg(), *dst, *to_f64);
|
||||||
|
|
||||||
let inst = Inst::jmp_known(BranchTarget::Label(done));
|
let inst = Inst::jmp_known(BranchTarget::Label(done));
|
||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
@@ -1842,10 +1853,8 @@ pub(crate) fn emit(
|
|||||||
|
|
||||||
// Divide x by two to get it in range for the signed conversion, keep the LSB, and
|
// Divide x by two to get it in range for the signed conversion, keep the LSB, and
|
||||||
// scale it back up on the FP side.
|
// scale it back up on the FP side.
|
||||||
if tmp_gpr1.to_reg() != *src {
|
let inst = Inst::gen_move(*tmp_gpr1, src.to_reg(), I64);
|
||||||
let inst = Inst::gen_move(*tmp_gpr1, *src, I64);
|
|
||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
}
|
|
||||||
|
|
||||||
// tmp_gpr1 := src >> 1
|
// tmp_gpr1 := src >> 1
|
||||||
let inst = Inst::shift_r(
|
let inst = Inst::shift_r(
|
||||||
@@ -1856,10 +1865,8 @@ pub(crate) fn emit(
|
|||||||
);
|
);
|
||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
|
|
||||||
if tmp_gpr2.to_reg() != *src {
|
let inst = Inst::gen_move(*tmp_gpr2, src.to_reg(), I64);
|
||||||
let inst = Inst::gen_move(*tmp_gpr2, *src, I64);
|
|
||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
}
|
|
||||||
|
|
||||||
let inst = Inst::alu_rmi_r(
|
let inst = Inst::alu_rmi_r(
|
||||||
true, /* 64bits */
|
true, /* 64bits */
|
||||||
@@ -2306,7 +2313,7 @@ pub(crate) fn emit(
|
|||||||
Inst::Ud2 { trap_info } => {
|
Inst::Ud2 { trap_info } => {
|
||||||
sink.add_trap(trap_info.0, trap_info.1);
|
sink.add_trap(trap_info.0, trap_info.1);
|
||||||
if let Some(s) = state.take_stackmap() {
|
if let Some(s) = state.take_stackmap() {
|
||||||
sink.add_stackmap(2, s);
|
sink.add_stackmap(StackmapExtent::UpcomingBytes(2), s);
|
||||||
}
|
}
|
||||||
sink.put1(0x0f);
|
sink.put1(0x0f);
|
||||||
sink.put1(0x0b);
|
sink.put1(0x0b);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//! This module defines x86_64-specific machine instruction types.
|
//! This module defines x86_64-specific machine instruction types.an explanation of what it's
|
||||||
|
//! doing.
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
@@ -83,7 +83,9 @@ pub enum Inst {
|
|||||||
CheckedDivOrRemSeq {
|
CheckedDivOrRemSeq {
|
||||||
kind: DivOrRemKind,
|
kind: DivOrRemKind,
|
||||||
size: u8,
|
size: u8,
|
||||||
divisor: Reg,
|
/// The divisor operand. Note it's marked as modified so that it gets assigned a register
|
||||||
|
/// different from the temporary.
|
||||||
|
divisor: Writable<Reg>,
|
||||||
tmp: Option<Writable<Reg>>,
|
tmp: Option<Writable<Reg>>,
|
||||||
loc: SourceLoc,
|
loc: SourceLoc,
|
||||||
},
|
},
|
||||||
@@ -236,11 +238,15 @@ pub enum Inst {
|
|||||||
src_size: OperandSize,
|
src_size: OperandSize,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Converts an unsigned int64 to a float64.
|
/// Converts an unsigned int64 to a float32/float64.
|
||||||
CvtUint64ToFloatSeq {
|
CvtUint64ToFloatSeq {
|
||||||
/// Is the target a 64-bits or 32-bits register?
|
/// Is the target a 64-bits or 32-bits register?
|
||||||
to_f64: bool,
|
to_f64: bool,
|
||||||
src: Reg,
|
/// A copy of the source register, fed by lowering. It is marked as modified during
|
||||||
|
/// register allocation to make sure that the temporary registers differ from the src
|
||||||
|
/// register, since both registers are live at the same time in the generated code
|
||||||
|
/// sequence.
|
||||||
|
src: Writable<Reg>,
|
||||||
dst: Writable<Reg>,
|
dst: Writable<Reg>,
|
||||||
tmp_gpr1: Writable<Reg>,
|
tmp_gpr1: Writable<Reg>,
|
||||||
tmp_gpr2: Writable<Reg>,
|
tmp_gpr2: Writable<Reg>,
|
||||||
@@ -442,6 +448,27 @@ impl Inst {
|
|||||||
Inst::MulHi { size, signed, rhs }
|
Inst::MulHi { size, signed, rhs }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn checked_div_or_rem_seq(
|
||||||
|
kind: DivOrRemKind,
|
||||||
|
size: u8,
|
||||||
|
divisor: Writable<Reg>,
|
||||||
|
tmp: Option<Writable<Reg>>,
|
||||||
|
loc: SourceLoc,
|
||||||
|
) -> Inst {
|
||||||
|
debug_assert!(size == 8 || size == 4 || size == 2 || size == 1);
|
||||||
|
debug_assert!(divisor.to_reg().get_class() == RegClass::I64);
|
||||||
|
debug_assert!(tmp
|
||||||
|
.map(|tmp| tmp.to_reg().get_class() == RegClass::I64)
|
||||||
|
.unwrap_or(true));
|
||||||
|
Inst::CheckedDivOrRemSeq {
|
||||||
|
kind,
|
||||||
|
size,
|
||||||
|
divisor,
|
||||||
|
tmp,
|
||||||
|
loc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn sign_extend_rax_to_rdx(size: u8) -> Inst {
|
pub(crate) fn sign_extend_rax_to_rdx(size: u8) -> Inst {
|
||||||
debug_assert!(size == 8 || size == 4 || size == 2);
|
debug_assert!(size == 8 || size == 4 || size == 2);
|
||||||
Inst::SignExtendRaxRdx { size }
|
Inst::SignExtendRaxRdx { size }
|
||||||
@@ -567,12 +594,12 @@ impl Inst {
|
|||||||
|
|
||||||
pub(crate) fn cvt_u64_to_float_seq(
|
pub(crate) fn cvt_u64_to_float_seq(
|
||||||
to_f64: bool,
|
to_f64: bool,
|
||||||
src: Reg,
|
src: Writable<Reg>,
|
||||||
tmp_gpr1: Writable<Reg>,
|
tmp_gpr1: Writable<Reg>,
|
||||||
tmp_gpr2: Writable<Reg>,
|
tmp_gpr2: Writable<Reg>,
|
||||||
dst: Writable<Reg>,
|
dst: Writable<Reg>,
|
||||||
) -> Inst {
|
) -> Inst {
|
||||||
debug_assert!(src.get_class() == RegClass::I64);
|
debug_assert!(src.to_reg().get_class() == RegClass::I64);
|
||||||
debug_assert!(tmp_gpr1.to_reg().get_class() == RegClass::I64);
|
debug_assert!(tmp_gpr1.to_reg().get_class() == RegClass::I64);
|
||||||
debug_assert!(tmp_gpr2.to_reg().get_class() == RegClass::I64);
|
debug_assert!(tmp_gpr2.to_reg().get_class() == RegClass::I64);
|
||||||
debug_assert!(dst.to_reg().get_class() == RegClass::V128);
|
debug_assert!(dst.to_reg().get_class() == RegClass::V128);
|
||||||
@@ -972,7 +999,7 @@ impl ShowWithRRU for Inst {
|
|||||||
DivOrRemKind::SignedRem => "srem",
|
DivOrRemKind::SignedRem => "srem",
|
||||||
DivOrRemKind::UnsignedRem => "urem",
|
DivOrRemKind::UnsignedRem => "urem",
|
||||||
},
|
},
|
||||||
show_ireg_sized(*divisor, mb_rru, *size),
|
show_ireg_sized(divisor.to_reg(), mb_rru, *size),
|
||||||
),
|
),
|
||||||
|
|
||||||
Inst::SignExtendRaxRdx { size } => match size {
|
Inst::SignExtendRaxRdx { size } => match size {
|
||||||
@@ -1072,7 +1099,7 @@ impl ShowWithRRU for Inst {
|
|||||||
"u64_to_{}_seq",
|
"u64_to_{}_seq",
|
||||||
if *to_f64 { "f64" } else { "f32" }
|
if *to_f64 { "f64" } else { "f32" }
|
||||||
)),
|
)),
|
||||||
show_ireg_sized(*src, mb_rru, 8),
|
show_ireg_sized(src.to_reg(), mb_rru, 8),
|
||||||
dst.show_rru(mb_rru),
|
dst.show_rru(mb_rru),
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -1363,14 +1390,14 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
|||||||
// the rdx register *before* the instruction, which is not too bad.
|
// the rdx register *before* the instruction, which is not too bad.
|
||||||
collector.add_mod(Writable::from_reg(regs::rax()));
|
collector.add_mod(Writable::from_reg(regs::rax()));
|
||||||
collector.add_mod(Writable::from_reg(regs::rdx()));
|
collector.add_mod(Writable::from_reg(regs::rdx()));
|
||||||
collector.add_use(*divisor);
|
collector.add_mod(*divisor);
|
||||||
if let Some(tmp) = tmp {
|
if let Some(tmp) = tmp {
|
||||||
collector.add_def(*tmp);
|
collector.add_def(*tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Inst::SignExtendRaxRdx { .. } => {
|
Inst::SignExtendRaxRdx { .. } => {
|
||||||
collector.add_use(regs::rax());
|
collector.add_use(regs::rax());
|
||||||
collector.add_mod(Writable::from_reg(regs::rdx()));
|
collector.add_def(Writable::from_reg(regs::rdx()));
|
||||||
}
|
}
|
||||||
Inst::UnaryRmR { src, dst, .. } | Inst::XmmUnaryRmR { src, dst, .. } => {
|
Inst::UnaryRmR { src, dst, .. } | Inst::XmmUnaryRmR { src, dst, .. } => {
|
||||||
src.get_regs_as_uses(collector);
|
src.get_regs_as_uses(collector);
|
||||||
@@ -1410,7 +1437,7 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
|||||||
tmp_gpr2,
|
tmp_gpr2,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
collector.add_use(*src);
|
collector.add_mod(*src);
|
||||||
collector.add_def(*dst);
|
collector.add_def(*dst);
|
||||||
collector.add_def(*tmp_gpr1);
|
collector.add_def(*tmp_gpr1);
|
||||||
collector.add_def(*tmp_gpr2);
|
collector.add_def(*tmp_gpr2);
|
||||||
@@ -1603,7 +1630,7 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
|||||||
Inst::Div { divisor, .. } => divisor.map_uses(mapper),
|
Inst::Div { divisor, .. } => divisor.map_uses(mapper),
|
||||||
Inst::MulHi { rhs, .. } => rhs.map_uses(mapper),
|
Inst::MulHi { rhs, .. } => rhs.map_uses(mapper),
|
||||||
Inst::CheckedDivOrRemSeq { divisor, tmp, .. } => {
|
Inst::CheckedDivOrRemSeq { divisor, tmp, .. } => {
|
||||||
map_use(mapper, divisor);
|
map_mod(mapper, divisor);
|
||||||
if let Some(tmp) = tmp {
|
if let Some(tmp) = tmp {
|
||||||
map_def(mapper, tmp)
|
map_def(mapper, tmp)
|
||||||
}
|
}
|
||||||
@@ -1683,7 +1710,7 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
|||||||
ref mut tmp_gpr2,
|
ref mut tmp_gpr2,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
map_use(mapper, src);
|
map_mod(mapper, src);
|
||||||
map_def(mapper, dst);
|
map_def(mapper, dst);
|
||||||
map_def(mapper, tmp_gpr1);
|
map_def(mapper, tmp_gpr1);
|
||||||
map_def(mapper, tmp_gpr2);
|
map_def(mapper, tmp_gpr2);
|
||||||
|
|||||||
@@ -240,6 +240,21 @@ fn emit_cmp(ctx: Ctx, insn: IRInst) {
|
|||||||
ctx.emit(Inst::cmp_rmi_r(ty.bytes() as u8, rhs, lhs));
|
ctx.emit(Inst::cmp_rmi_r(ty.bytes() as u8, rhs, lhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_fcmp(ctx: Ctx, insn: IRInst) {
|
||||||
|
// The only valid CC constructed with `from_floatcc` can be put in the flag
|
||||||
|
// register with a direct float comparison; do this here.
|
||||||
|
let input_ty = ctx.input_ty(insn, 0);
|
||||||
|
let op = match input_ty {
|
||||||
|
F32 => SseOpcode::Ucomiss,
|
||||||
|
F64 => SseOpcode::Ucomisd,
|
||||||
|
_ => panic!("Bad input type to Fcmp"),
|
||||||
|
};
|
||||||
|
let inputs = &[InsnInput { insn, input: 0 }, InsnInput { insn, input: 1 }];
|
||||||
|
let lhs = input_to_reg(ctx, inputs[0]);
|
||||||
|
let rhs = input_to_reg_mem(ctx, inputs[1]);
|
||||||
|
ctx.emit(Inst::xmm_cmp_rm_r(op, rhs, lhs));
|
||||||
|
}
|
||||||
|
|
||||||
fn make_libcall_sig(ctx: Ctx, insn: IRInst, call_conv: CallConv, ptr_ty: Type) -> Signature {
|
fn make_libcall_sig(ctx: Ctx, insn: IRInst, call_conv: CallConv, ptr_ty: Type) -> Signature {
|
||||||
let mut sig = Signature::new(call_conv);
|
let mut sig = Signature::new(call_conv);
|
||||||
for i in 0..ctx.num_inputs(insn) {
|
for i in 0..ctx.num_inputs(insn) {
|
||||||
@@ -782,9 +797,15 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
let dst = output_to_reg(ctx, outputs[0]);
|
let dst = output_to_reg(ctx, outputs[0]);
|
||||||
let ty = ctx.input_ty(insn, 0);
|
let ty = ctx.input_ty(insn, 0);
|
||||||
let imm = match op {
|
let imm = match op {
|
||||||
|
Opcode::IsNull => {
|
||||||
// TODO could use tst src, src for IsNull
|
// TODO could use tst src, src for IsNull
|
||||||
Opcode::IsNull => 0,
|
0
|
||||||
Opcode::IsInvalid => 0xffffffff,
|
}
|
||||||
|
Opcode::IsInvalid => {
|
||||||
|
// We can do a 32-bit comparison even in 64-bits mode, as the constant is then
|
||||||
|
// sign-extended.
|
||||||
|
0xffffffff
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
ctx.emit(Inst::cmp_rmi_r(ty.bytes() as u8, RegMemImm::imm(imm), src));
|
ctx.emit(Inst::cmp_rmi_r(ty.bytes() as u8, RegMemImm::imm(imm), src));
|
||||||
@@ -1026,30 +1047,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
|
|
||||||
// Verification ensures that the input is always a single-def ffcmp.
|
// Verification ensures that the input is always a single-def ffcmp.
|
||||||
let ffcmp_insn = matches_input(ctx, inputs[0], Opcode::Ffcmp).unwrap();
|
let ffcmp_insn = matches_input(ctx, inputs[0], Opcode::Ffcmp).unwrap();
|
||||||
{
|
emit_fcmp(ctx, ffcmp_insn);
|
||||||
// The only valid CC constructed with `from_floatcc` can be put in the flag
|
|
||||||
// register with a direct float comparison; do this here.
|
|
||||||
let input_ty = ctx.input_ty(ffcmp_insn, 0);
|
|
||||||
let op = match input_ty {
|
|
||||||
F32 => SseOpcode::Ucomiss,
|
|
||||||
F64 => SseOpcode::Ucomisd,
|
|
||||||
_ => panic!("Bad input type to Fcmp"),
|
|
||||||
};
|
|
||||||
let inputs = &[
|
|
||||||
InsnInput {
|
|
||||||
insn: ffcmp_insn,
|
|
||||||
input: 0,
|
|
||||||
},
|
|
||||||
InsnInput {
|
|
||||||
insn: ffcmp_insn,
|
|
||||||
input: 1,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
let lhs = input_to_reg(ctx, inputs[0]);
|
|
||||||
let rhs = input_to_reg_mem(ctx, inputs[1]);
|
|
||||||
ctx.emit(Inst::xmm_cmp_rm_r(op, rhs, lhs));
|
|
||||||
}
|
|
||||||
|
|
||||||
cc
|
cc
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1203,11 +1201,15 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
|
|
||||||
I64 => {
|
I64 => {
|
||||||
let src = input_to_reg(ctx, inputs[0]);
|
let src = input_to_reg(ctx, inputs[0]);
|
||||||
|
|
||||||
|
let src_copy = ctx.alloc_tmp(RegClass::I64, I64);
|
||||||
|
ctx.emit(Inst::gen_move(src_copy, src, I64));
|
||||||
|
|
||||||
let tmp_gpr1 = ctx.alloc_tmp(RegClass::I64, I64);
|
let tmp_gpr1 = ctx.alloc_tmp(RegClass::I64, I64);
|
||||||
let tmp_gpr2 = ctx.alloc_tmp(RegClass::I64, I64);
|
let tmp_gpr2 = ctx.alloc_tmp(RegClass::I64, I64);
|
||||||
ctx.emit(Inst::cvt_u64_to_float_seq(
|
ctx.emit(Inst::cvt_u64_to_float_seq(
|
||||||
ty == F64,
|
ty == F64,
|
||||||
src,
|
src_copy,
|
||||||
tmp_gpr1,
|
tmp_gpr1,
|
||||||
tmp_gpr2,
|
tmp_gpr2,
|
||||||
dst,
|
dst,
|
||||||
@@ -1729,19 +1731,23 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
// regalloc is aware of the coalescing opportunity between rax/rdx and the
|
// regalloc is aware of the coalescing opportunity between rax/rdx and the
|
||||||
// destination register.
|
// destination register.
|
||||||
let divisor = input_to_reg(ctx, inputs[1]);
|
let divisor = input_to_reg(ctx, inputs[1]);
|
||||||
|
|
||||||
|
let divisor_copy = ctx.alloc_tmp(RegClass::I64, I64);
|
||||||
|
ctx.emit(Inst::gen_move(divisor_copy, divisor, I64));
|
||||||
|
|
||||||
let tmp = if op == Opcode::Sdiv && size == 8 {
|
let tmp = if op == Opcode::Sdiv && size == 8 {
|
||||||
Some(ctx.alloc_tmp(RegClass::I64, I64))
|
Some(ctx.alloc_tmp(RegClass::I64, I64))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
ctx.emit(Inst::imm_r(true, 0, Writable::from_reg(regs::rdx())));
|
ctx.emit(Inst::imm_r(true, 0, Writable::from_reg(regs::rdx())));
|
||||||
ctx.emit(Inst::CheckedDivOrRemSeq {
|
ctx.emit(Inst::checked_div_or_rem_seq(
|
||||||
kind,
|
kind,
|
||||||
size,
|
size,
|
||||||
divisor,
|
divisor_copy,
|
||||||
tmp,
|
tmp,
|
||||||
loc: srcloc,
|
srcloc,
|
||||||
});
|
));
|
||||||
} else {
|
} else {
|
||||||
let divisor = input_to_reg_mem(ctx, inputs[1]);
|
let divisor = input_to_reg_mem(ctx, inputs[1]);
|
||||||
|
|
||||||
|
|||||||
@@ -258,8 +258,20 @@ impl MachLabel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A stackmap extent, when creating a stackmap.
|
||||||
|
pub enum StackmapExtent {
|
||||||
|
/// The stack map starts at this instruction, and ends after the number of upcoming bytes
|
||||||
|
/// (note: this is a code offset diff).
|
||||||
|
UpcomingBytes(CodeOffset),
|
||||||
|
|
||||||
|
/// The stack map started at the given offset and ends at the current one. This helps
|
||||||
|
/// architectures where the instruction size has not a fixed length.
|
||||||
|
StartedAtOffset(CodeOffset),
|
||||||
|
}
|
||||||
|
|
||||||
impl<I: VCodeInst> MachBuffer<I> {
|
impl<I: VCodeInst> MachBuffer<I> {
|
||||||
/// Create a new section, known to start at `start_offset` and with a size limited to `length_limit`.
|
/// Create a new section, known to start at `start_offset` and with a size limited to
|
||||||
|
/// `length_limit`.
|
||||||
pub fn new() -> MachBuffer<I> {
|
pub fn new() -> MachBuffer<I> {
|
||||||
MachBuffer {
|
MachBuffer {
|
||||||
data: SmallVec::new(),
|
data: SmallVec::new(),
|
||||||
@@ -1159,32 +1171,27 @@ impl<I: VCodeInst> MachBuffer<I> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add stackmap metadata for this program point: a set of stack offsets
|
/// Add stackmap metadata for this program point: a set of stack offsets (from SP upward) that
|
||||||
/// (from SP upward) that contain live references.
|
/// contain live references.
|
||||||
///
|
///
|
||||||
/// The `offset_to_fp` value is the offset from the nominal SP (at which the
|
/// The `offset_to_fp` value is the offset from the nominal SP (at which the `stack_offsets`
|
||||||
/// `stack_offsets` are based) and the FP value. By subtracting
|
/// are based) and the FP value. By subtracting `offset_to_fp` from each `stack_offsets`
|
||||||
/// `offset_to_fp` from each `stack_offsets` element, one can obtain
|
/// element, one can obtain live-reference offsets from FP instead.
|
||||||
/// live-reference offsets from FP instead.
|
pub fn add_stackmap(&mut self, extent: StackmapExtent, stackmap: Stackmap) {
|
||||||
pub fn add_stackmap(&mut self, insn_len: CodeOffset, stackmap: Stackmap) {
|
let (start, end) = match extent {
|
||||||
let offset = self.cur_offset();
|
StackmapExtent::UpcomingBytes(insn_len) => {
|
||||||
self.stackmaps.push(MachStackMap {
|
let start_offset = self.cur_offset();
|
||||||
offset,
|
(start_offset, start_offset + insn_len)
|
||||||
offset_end: offset + insn_len,
|
|
||||||
stackmap,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
StackmapExtent::StartedAtOffset(start_offset) => {
|
||||||
/// Add stackmap metadata for this program point: a set of stack offsets
|
let end_offset = self.cur_offset();
|
||||||
/// (from SP upward) that contain live references.
|
debug_assert!(end_offset >= start_offset);
|
||||||
///
|
(start_offset, end_offset)
|
||||||
/// Method variant of `add_stackmap` that is easier to manipulate for non-fixed-sizes
|
}
|
||||||
/// instructions.
|
};
|
||||||
pub fn add_stackmap_ending_at(&mut self, start_offset: CodeOffset, stackmap: Stackmap) {
|
|
||||||
let cur_offset = self.cur_offset();
|
|
||||||
self.stackmaps.push(MachStackMap {
|
self.stackmaps.push(MachStackMap {
|
||||||
offset: start_offset,
|
offset: start,
|
||||||
offset_end: cur_offset,
|
offset_end: end,
|
||||||
stackmap,
|
stackmap,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user