mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-17 10:51:21 +00:00
Up to 1242 passing spectests
This commit is contained in:
@ -3,8 +3,8 @@ use inkwell::{
|
||||
context::Context,
|
||||
module::{Linkage, Module},
|
||||
passes::PassManager,
|
||||
types::{BasicType, BasicTypeEnum, FunctionType, PointerType},
|
||||
values::{BasicValue, FunctionValue, PhiValue, PointerValue},
|
||||
types::{BasicType, BasicTypeEnum, FunctionType, IntType, PointerType},
|
||||
values::{BasicValue, FunctionValue, IntValue, PhiValue, PointerValue},
|
||||
AddressSpace, FloatPredicate, IntPredicate,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
@ -613,7 +613,7 @@ fn parse_function(
|
||||
let global_cache = ctx.global_cache(index);
|
||||
match global_cache {
|
||||
GlobalCache::Const { value } => {
|
||||
state.push1(value.as_basic_value_enum());
|
||||
state.push1(value);
|
||||
}
|
||||
GlobalCache::Mut { ptr_to_value } => {
|
||||
let value = builder.build_load(ptr_to_value, "global_value");
|
||||
@ -882,24 +882,36 @@ fn parse_function(
|
||||
Operator::I32DivS | Operator::I64DivS => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
|
||||
trap_if_zero_or_overflow(builder, intrinsics, context, &function, v1, v2);
|
||||
|
||||
let res = builder.build_int_signed_div(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32DivU | Operator::I64DivU => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
|
||||
trap_if_zero(builder, intrinsics, context, &function, v2);
|
||||
|
||||
let res = builder.build_int_unsigned_div(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32RemS | Operator::I64RemS => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
|
||||
trap_if_zero(builder, intrinsics, context, &function, v2);
|
||||
|
||||
let res = builder.build_int_signed_rem(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32RemU | Operator::I64RemU => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
|
||||
trap_if_zero(builder, intrinsics, context, &function, v2);
|
||||
|
||||
let res = builder.build_int_unsigned_rem(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
@ -2001,6 +2013,112 @@ fn parse_function(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn trap_if_zero_or_overflow(
|
||||
builder: &Builder,
|
||||
intrinsics: &Intrinsics,
|
||||
context: &Context,
|
||||
function: &FunctionValue,
|
||||
left: IntValue,
|
||||
right: IntValue,
|
||||
) {
|
||||
let int_type = left.get_type();
|
||||
|
||||
let (min_value, neg_one_value) = if int_type == intrinsics.i32_ty {
|
||||
let min_value = int_type.const_int(i32::min_value() as u64, false);
|
||||
let neg_one_value = int_type.const_int(-1i32 as u32 as u64, false);
|
||||
(min_value, neg_one_value)
|
||||
} else if int_type == intrinsics.i64_ty {
|
||||
let min_value = int_type.const_int(i64::min_value() as u64, false);
|
||||
let neg_one_value = int_type.const_int(-1i64 as u64, false);
|
||||
(min_value, neg_one_value)
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let should_trap = builder.build_or(
|
||||
builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
right,
|
||||
int_type.const_int(0, false),
|
||||
"divisor_is_zero",
|
||||
),
|
||||
builder.build_and(
|
||||
builder.build_int_compare(IntPredicate::EQ, left, min_value, "left_is_min"),
|
||||
builder.build_int_compare(IntPredicate::EQ, right, neg_one_value, "right_is_neg_one"),
|
||||
"div_will_overflow",
|
||||
),
|
||||
"div_should_trap",
|
||||
);
|
||||
|
||||
let should_trap = builder
|
||||
.build_call(
|
||||
intrinsics.expect_i1,
|
||||
&[
|
||||
should_trap.as_basic_value_enum(),
|
||||
intrinsics.i1_ty.const_int(0, false).as_basic_value_enum(),
|
||||
],
|
||||
"should_trap_expect",
|
||||
)
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let shouldnt_trap_block = context.append_basic_block(function, "shouldnt_trap_block");
|
||||
let should_trap_block = context.append_basic_block(function, "should_trap_block");
|
||||
builder.build_conditional_branch(should_trap, &should_trap_block, &shouldnt_trap_block);
|
||||
builder.position_at_end(&should_trap_block);
|
||||
builder.build_call(
|
||||
intrinsics.throw_trap,
|
||||
&[intrinsics.trap_memory_oob],
|
||||
"throw",
|
||||
);
|
||||
builder.build_unreachable();
|
||||
builder.position_at_end(&shouldnt_trap_block);
|
||||
}
|
||||
|
||||
fn trap_if_zero(
|
||||
builder: &Builder,
|
||||
intrinsics: &Intrinsics,
|
||||
context: &Context,
|
||||
function: &FunctionValue,
|
||||
value: IntValue,
|
||||
) {
|
||||
let int_type = value.get_type();
|
||||
let should_trap = builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
value,
|
||||
int_type.const_int(0, false),
|
||||
"divisor_is_zero",
|
||||
);
|
||||
|
||||
let should_trap = builder
|
||||
.build_call(
|
||||
intrinsics.expect_i1,
|
||||
&[
|
||||
should_trap.as_basic_value_enum(),
|
||||
intrinsics.i1_ty.const_int(0, false).as_basic_value_enum(),
|
||||
],
|
||||
"should_trap_expect",
|
||||
)
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let shouldnt_trap_block = context.append_basic_block(function, "shouldnt_trap_block");
|
||||
let should_trap_block = context.append_basic_block(function, "should_trap_block");
|
||||
builder.build_conditional_branch(should_trap, &should_trap_block, &shouldnt_trap_block);
|
||||
builder.position_at_end(&should_trap_block);
|
||||
builder.build_call(
|
||||
intrinsics.throw_trap,
|
||||
&[intrinsics.trap_memory_oob],
|
||||
"throw",
|
||||
);
|
||||
builder.build_unreachable();
|
||||
builder.position_at_end(&shouldnt_trap_block);
|
||||
}
|
||||
|
||||
fn resolve_memory_ptr(
|
||||
builder: &Builder,
|
||||
intrinsics: &Intrinsics,
|
||||
|
@ -419,7 +419,7 @@ struct TableCache {
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum GlobalCache {
|
||||
Mut { ptr_to_value: PointerValue },
|
||||
Const { value: IntValue },
|
||||
Const { value: BasicValueEnum },
|
||||
}
|
||||
|
||||
struct ImportedFuncCache {
|
||||
@ -675,11 +675,8 @@ impl<'a> CtxType<'a> {
|
||||
.build_load(global_ptr_ptr, "global_ptr")
|
||||
.into_pointer_value();
|
||||
|
||||
let global_ptr_typed = {
|
||||
let int =
|
||||
cache_builder.build_ptr_to_int(global_ptr, intrinsics.i64_ty, "global_ptr_int");
|
||||
cache_builder.build_int_to_ptr(int, llvm_ptr_ty, "global_ptr_typed")
|
||||
};
|
||||
let global_ptr_typed =
|
||||
cache_builder.build_pointer_cast(global_ptr, llvm_ptr_ty, "global_ptr_typed");
|
||||
|
||||
if mutable {
|
||||
GlobalCache::Mut {
|
||||
@ -687,9 +684,7 @@ impl<'a> CtxType<'a> {
|
||||
}
|
||||
} else {
|
||||
GlobalCache::Const {
|
||||
value: cache_builder
|
||||
.build_load(global_ptr_typed, "global_value")
|
||||
.into_int_value(),
|
||||
value: cache_builder.build_load(global_ptr_typed, "global_value"),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
Reference in New Issue
Block a user