machinst x64: implement support for dynamic heaps and explicit bound checks;

This commit is contained in:
Benjamin Bouvier
2020-07-23 14:57:23 +02:00
parent 2e3ad3227d
commit 987c616bf5
5 changed files with 109 additions and 35 deletions

View File

@@ -122,6 +122,27 @@ 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.
pub fn to_static_str(self) -> &'static str {
use self::IntCC::*;

View File

@@ -798,27 +798,6 @@ pub(crate) fn lower_vector_compare<C: LowerCtx<I = Inst>>(
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 fn condcode_is_signed(cc: IntCC) -> bool {
match cc {
IntCC::Equal => false,
IntCC::NotEqual => false,
IntCC::SignedGreaterThanOrEqual => true,
IntCC::SignedGreaterThan => true,
IntCC::SignedLessThanOrEqual => true,
IntCC::SignedLessThan => true,
IntCC::UnsignedGreaterThanOrEqual => false,
IntCC::UnsignedGreaterThan => false,
IntCC::UnsignedLessThanOrEqual => false,
IntCC::UnsignedLessThan => false,
IntCC::Overflow => true,
IntCC::NotOverflow => true,
}
}
//=============================================================================
// Helpers for instruction lowering.

View File

@@ -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 cond = lower_condcode(condcode);
let is_signed = condcode_is_signed(condcode);
let is_signed = condcode.is_signed();
lower_icmp_or_ifcmp_to_flags(ctx, icmp_insn, is_signed);
cond
} 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 => {
let condcode = inst_condcode(ctx.data(insn)).unwrap();
let cond = lower_condcode(condcode);
let is_signed = condcode_is_signed(condcode);
let is_signed = condcode.is_signed();
// Verification ensures that the input is always a
// single-def ifcmp.
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 => {
let condcode = inst_condcode(ctx.data(insn)).unwrap();
let cond = lower_condcode(condcode);
let is_signed = condcode_is_signed(condcode);
let is_signed = condcode.is_signed();
// Verification ensures that the input is always a
// single-def ifcmp.
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 => {
let condcode = inst_condcode(ctx.data(insn)).unwrap();
let cond = lower_condcode(condcode);
let is_signed = condcode_is_signed(condcode);
let is_signed = condcode.is_signed();
let rd = get_output_reg(ctx, outputs[0]);
let ty = ctx.input_ty(insn, 0);
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 {
let condcode = inst_condcode(ctx.data(insn)).unwrap();
let cond = lower_condcode(condcode);
let is_signed = condcode_is_signed(condcode);
let is_signed = condcode.is_signed();
// Verification ensures that the input is always a single-def ifcmp.
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 cond = lower_condcode(condcode);
let is_signed = condcode_is_signed(condcode);
let is_signed = condcode.is_signed();
let negated = op0 == Opcode::Brz;
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 kind = CondBrKind::Cond(cond);
let is_signed = condcode_is_signed(condcode);
let is_signed = condcode.is_signed();
let ty = ctx.input_ty(branches[0], 0);
let bits = ty_bits(ty);
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 kind = CondBrKind::Cond(cond);
let is_signed = condcode_is_signed(condcode);
let is_signed = condcode.is_signed();
let flag_input = InsnInput {
insn: branches[0],
input: 0,

View File

@@ -726,9 +726,9 @@ impl CC {
| FloatCC::LessThan
| FloatCC::LessThanOrEqual
| FloatCC::UnorderedOrGreaterThan
| FloatCC::UnorderedOrGreaterThanOrEqual => unimplemented!(
"No single condition code to guarantee ordered. Treat as special case."
),
| FloatCC::UnorderedOrGreaterThanOrEqual => {
panic!("No single condition code to guarantee ordered. Treat as special case.")
}
}
}

View File

@@ -135,6 +135,17 @@ struct InsnOutput {
output: usize,
}
fn matches_input<C: LowerCtx<I = Inst>>(c: &mut C, input: InsnInput, op: Opcode) -> Option<IRInst> {
let inputs = c.get_input(input.insn, input.input);
if let Some((src_inst, _)) = inputs.inst {
let data = c.data(src_inst);
if data.opcode() == op {
return Some(src_inst);
}
}
None
}
fn input_to_reg(ctx: Ctx, spec: InsnInput) -> Reg {
let inputs = ctx.get_input(spec.insn, spec.input);
ctx.use_input_reg(inputs);
@@ -328,7 +339,13 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
}
}
Opcode::Iadd | Opcode::Isub | Opcode::Imul | Opcode::Band | Opcode::Bor | Opcode::Bxor => {
Opcode::Iadd
| Opcode::IaddIfcout
| Opcode::Isub
| Opcode::Imul
| Opcode::Band
| Opcode::Bor
| Opcode::Bxor => {
let lhs = input_to_reg(ctx, inputs[0]);
let rhs = input_to_reg_mem_imm(ctx, inputs[1]);
let dst = output_to_reg(ctx, outputs[0]);
@@ -338,7 +355,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
let is_64 = int_ty_is_64(ty.unwrap());
let alu_op = match op {
Opcode::Iadd => AluRmiROpcode::Add,
Opcode::Iadd | Opcode::IaddIfcout => AluRmiROpcode::Add,
Opcode::Isub => AluRmiROpcode::Sub,
Opcode::Imul => AluRmiROpcode::Mul,
Opcode::Band => AluRmiROpcode::And,
@@ -965,6 +982,64 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(Inst::Ud2 { trap_info })
}
Opcode::Trapif | Opcode::Trapff => {
let srcloc = ctx.srcloc(insn);
let trap_code = inst_trapcode(ctx.data(insn)).unwrap();
let cc = if matches_input(ctx, inputs[0], Opcode::IaddIfcout).is_some() {
let condcode = inst_condcode(ctx.data(insn));
// The flags must not have been clobbered by any other instruction between the
// iadd_ifcout and this instruction, as verified by the CLIF validator; so we can
// simply use the flags here.
CC::from_intcc(condcode)
} else if op == Opcode::Trapif {
let condcode = inst_condcode(ctx.data(insn));
let cc = CC::from_intcc(condcode);
// Verification ensures that the input is always a single-def ifcmp.
let ifcmp_insn = matches_input(ctx, inputs[0], Opcode::Ifcmp).unwrap();
emit_cmp(ctx, ifcmp_insn);
cc
} else {
let condcode = inst_fp_condcode(ctx.data(insn)).unwrap();
let cc = CC::from_floatcc(condcode);
// Verification ensures that the input is always a single-def ffcmp.
let ffcmp_insn = matches_input(ctx, inputs[0], Opcode::Ffcmp).unwrap();
{
// 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
};
ctx.emit(Inst::TrapIf {
trap_code,
srcloc,
cc,
});
}
Opcode::F64const => {
// TODO use xorpd for 0
let value = ctx.get_constant(insn).unwrap();
@@ -1724,7 +1799,6 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
| Opcode::IaddCin
| Opcode::IaddIfcin
| Opcode::IaddCout
| Opcode::IaddIfcout
| Opcode::IaddCarry
| Opcode::IaddIfcarry
| Opcode::IsubBin