Check for invalid special type constraints.
The extend and reduce instructions have additional type constraints. Stop inserting sextend instructions after ctz, clz, and popcnt when translating from WebAssembly. The Cretonne instructions have the same signature as the WebAssembly equivalents.
This commit is contained in:
@@ -95,3 +95,17 @@ function %jump_args2() {
|
||||
ebb1(v10: i64, v11: i16):
|
||||
return
|
||||
}
|
||||
|
||||
function %bad_extend() {
|
||||
ebb0:
|
||||
v0 = iconst.i32 10
|
||||
v1 = uextend.i16 v0 ; error: input i32 must be smaller than output i16
|
||||
return
|
||||
}
|
||||
|
||||
function %bad_reduce() {
|
||||
ebb0:
|
||||
v0 = iconst.i32 10
|
||||
v1 = ireduce.i64 v0 ; error: input i32 must be larger than output i64
|
||||
return
|
||||
}
|
||||
|
||||
@@ -49,8 +49,6 @@
|
||||
//!
|
||||
//! - Stack slot loads and stores must be in-bounds.
|
||||
//! - Immediate constraints for certain opcodes, like `udiv_imm v3, 0`.
|
||||
//! - Extend / truncate instructions have more type constraints: Source type can't be
|
||||
//! larger / smaller than result type.
|
||||
//! - `Insertlane` and `extractlane` instructions have immediate lane numbers that must be in
|
||||
//! range for their polymorphic type.
|
||||
//! - Swizzle and shuffle instructions take a variable number of lane arguments. The number
|
||||
@@ -574,6 +572,7 @@ impl<'a> Verifier<'a> {
|
||||
self.typecheck_fixed_args(inst, ctrl_type)?;
|
||||
self.typecheck_variable_args(inst)?;
|
||||
self.typecheck_return(inst)?;
|
||||
self.typecheck_special(inst, ctrl_type)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -818,6 +817,57 @@ impl<'a> Verifier<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Check special-purpose type constraints that can't be expressed in the normal opcode
|
||||
// constraints.
|
||||
fn typecheck_special(&self, inst: Inst, ctrl_type: Type) -> Result {
|
||||
match self.func.dfg[inst] {
|
||||
ir::InstructionData::Unary { opcode, arg } => {
|
||||
let arg_type = self.func.dfg.value_type(arg);
|
||||
match opcode {
|
||||
Opcode::Bextend | Opcode::Uextend | Opcode::Sextend | Opcode::Fpromote => {
|
||||
if arg_type.lane_count() != ctrl_type.lane_count() {
|
||||
return err!(
|
||||
inst,
|
||||
"input {} and output {} must have same number of lanes",
|
||||
arg_type,
|
||||
ctrl_type
|
||||
);
|
||||
}
|
||||
if arg_type.lane_bits() >= ctrl_type.lane_bits() {
|
||||
return err!(
|
||||
inst,
|
||||
"input {} must be smaller than output {}",
|
||||
arg_type,
|
||||
ctrl_type
|
||||
);
|
||||
}
|
||||
}
|
||||
Opcode::Breduce | Opcode::Ireduce | Opcode::Fdemote => {
|
||||
if arg_type.lane_count() != ctrl_type.lane_count() {
|
||||
return err!(
|
||||
inst,
|
||||
"input {} and output {} must have same number of lanes",
|
||||
arg_type,
|
||||
ctrl_type
|
||||
);
|
||||
}
|
||||
if arg_type.lane_bits() <= ctrl_type.lane_bits() {
|
||||
return err!(
|
||||
inst,
|
||||
"input {} must be larger than output {}",
|
||||
arg_type,
|
||||
ctrl_type
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cfg_integrity(&self, cfg: &ControlFlowGraph) -> Result {
|
||||
let mut expected_succs = BTreeSet::<Ebb>::new();
|
||||
let mut got_succs = BTreeSet::<Ebb>::new();
|
||||
|
||||
@@ -486,33 +486,27 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
/******************************* Unary Operators *************************************/
|
||||
Operator::I32Clz => {
|
||||
let arg = state.pop1();
|
||||
let val = builder.ins().clz(arg);
|
||||
state.push1(builder.ins().sextend(I32, val));
|
||||
state.push1(builder.ins().clz(arg));
|
||||
}
|
||||
Operator::I64Clz => {
|
||||
let arg = state.pop1();
|
||||
let val = builder.ins().clz(arg);
|
||||
state.push1(builder.ins().sextend(I64, val));
|
||||
state.push1(builder.ins().clz(arg));
|
||||
}
|
||||
Operator::I32Ctz => {
|
||||
let val = state.pop1();
|
||||
let short_res = builder.ins().ctz(val);
|
||||
state.push1(builder.ins().sextend(I32, short_res));
|
||||
let arg = state.pop1();
|
||||
state.push1(builder.ins().ctz(arg));
|
||||
}
|
||||
Operator::I64Ctz => {
|
||||
let val = state.pop1();
|
||||
let short_res = builder.ins().ctz(val);
|
||||
state.push1(builder.ins().sextend(I64, short_res));
|
||||
let arg = state.pop1();
|
||||
state.push1(builder.ins().ctz(arg));
|
||||
}
|
||||
Operator::I32Popcnt => {
|
||||
let arg = state.pop1();
|
||||
let val = builder.ins().popcnt(arg);
|
||||
state.push1(builder.ins().sextend(I32, val));
|
||||
state.push1(builder.ins().popcnt(arg));
|
||||
}
|
||||
Operator::I64Popcnt => {
|
||||
let arg = state.pop1();
|
||||
let val = builder.ins().popcnt(arg);
|
||||
state.push1(builder.ins().sextend(I64, val));
|
||||
state.push1(builder.ins().popcnt(arg));
|
||||
}
|
||||
Operator::I64ExtendSI32 => {
|
||||
let val = state.pop1();
|
||||
|
||||
Reference in New Issue
Block a user