Rewrite trans_cast, float->float and float->int casts

This commit is contained in:
Marijn Haverbeke 2011-07-22 13:10:59 +02:00
parent 5864d4e13a
commit b45d973552
4 changed files with 71 additions and 48 deletions

View file

@ -1543,6 +1543,16 @@ fn type_to_str_inner(type_names names, &TypeRef[] outer0, TypeRef ty) -> str {
}
}
fn float_width(TypeRef llt) -> uint {
ret alt llvm::LLVMGetTypeKind(llt) {
1 { 32u }
2 { 64u }
3 { 80u }
4 | 5 { 128u }
_ { fail "llvm_float_width called on a non-float type"; 0u }
};
}
fn fn_ty_param_tys(TypeRef fn_ty) -> TypeRef[] {
auto args = ivec::init_elt(0 as TypeRef,
llvm::LLVMCountParamTypes(fn_ty));

View file

@ -4403,60 +4403,73 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result {
fn int_cast(&@block_ctxt bcx, TypeRef lldsttype, TypeRef llsrctype,
ValueRef llsrc, bool signed) -> ValueRef {
if (llvm::LLVMGetIntTypeWidth(lldsttype) >
llvm::LLVMGetIntTypeWidth(llsrctype)) {
if (signed) {
// Widening signed cast.
auto srcsz = llvm::LLVMGetIntTypeWidth(llsrctype);
auto dstsz = llvm::LLVMGetIntTypeWidth(lldsttype);
ret if dstsz == srcsz { bcx.build.BitCast(llsrc, lldsttype) }
else if srcsz > dstsz { bcx.build.TruncOrBitCast(llsrc, lldsttype) }
else if signed { bcx.build.SExtOrBitCast(llsrc, lldsttype) }
else { bcx.build.ZExtOrBitCast(llsrc, lldsttype) };
}
ret bcx.build.SExtOrBitCast(llsrc, lldsttype);
}
// Widening unsigned cast.
ret bcx.build.ZExtOrBitCast(llsrc, lldsttype);
}
ret bcx.build.TruncOrBitCast(llsrc, lldsttype);
fn float_cast(&@block_ctxt bcx, TypeRef lldsttype, TypeRef llsrctype,
ValueRef llsrc) -> ValueRef {
auto srcsz = lib::llvm::float_width(llsrctype);
auto dstsz = lib::llvm::float_width(lldsttype);
ret if dstsz > srcsz { bcx.build.FPExt(llsrc, lldsttype) }
else if srcsz > dstsz { bcx.build.FPTrunc(llsrc, lldsttype) }
else { llsrc };
}
fn trans_cast(&@block_ctxt cx, &@ast::expr e, ast::node_id id) -> result {
auto ccx = cx.fcx.lcx.ccx;
auto e_res = trans_expr(cx, e);
auto llsrctype = val_ty(e_res.val);
auto t = node_id_type(cx.fcx.lcx.ccx, id);
auto lldsttype = type_of(cx.fcx.lcx.ccx, e.span, t);
if (!ty::type_is_fp(cx.fcx.lcx.ccx.tcx, t)) {
auto ll_t_in = val_ty(e_res.val);
auto t_in = ty::expr_ty(ccx.tcx, e);
auto t_out = node_id_type(ccx, id);
auto ll_t_out = type_of(ccx, e.span, t_out);
// TODO: native-to-native casts
if (ty::type_is_native(cx.fcx.lcx.ccx.tcx,
ty::expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
e_res =
rslt(e_res.bcx,
e_res.bcx.build.PtrToInt(e_res.val, lldsttype));
} else if (ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
e_res =
rslt(e_res.bcx,
e_res.bcx.build.IntToPtr(e_res.val, lldsttype));
} else {
e_res =
rslt(e_res.bcx,
int_cast(e_res.bcx, lldsttype, llsrctype, e_res.val,
ty::type_is_signed(cx.fcx.lcx.ccx.tcx, t)));
}
tag kind { native_; integral; float; other; }
fn t_kind(&ty::ctxt tcx, ty::t t) -> kind {
ret if ty::type_is_fp(tcx, t) { float }
else if ty::type_is_native(tcx, t) { native_ }
else if ty::type_is_integral(tcx, t) { integral }
else { other };
}
else {
if (ty::type_is_integral(cx.fcx.lcx.ccx.tcx,
ty::expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
if (ty::type_is_signed(cx.fcx.lcx.ccx.tcx,
ty::expr_ty(cx.fcx.lcx.ccx.tcx, e))) {
e_res = rslt(e_res.bcx,
e_res.bcx.build.SIToFP(e_res.val, lldsttype));
}
else {
e_res = rslt(e_res.bcx,
e_res.bcx.build.UIToFP(e_res.val, lldsttype));
}
}
else { cx.fcx.lcx.ccx.sess.unimpl("fp cast"); }
}
ret e_res;
auto k_in = t_kind(ccx.tcx, t_in);
auto k_out = t_kind(ccx.tcx, t_out);
auto s_in = k_in == integral && ty::type_is_signed(ccx.tcx, t_in);
auto newval = alt rec(in=k_in, out=k_out) {
{in: integral, out: integral} {
int_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val, s_in)
}
{in: float, out: float} {
float_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val)
}
{in: integral, out: float} {
if s_in { e_res.bcx.build.SIToFP(e_res.val, ll_t_out) }
else { e_res.bcx.build.UIToFP(e_res.val, ll_t_out) }
}
{in: float, out: integral} {
if ty::type_is_signed(ccx.tcx, t_out) {
e_res.bcx.build.FPToSI(e_res.val, ll_t_out)
} else { e_res.bcx.build.FPToUI(e_res.val, ll_t_out) }
}
{in: integral, out: native_} {
e_res.bcx.build.IntToPtr(e_res.val, ll_t_out)
}
{in: native_, out: integral} {
e_res.bcx.build.PtrToInt(e_res.val, ll_t_out)
}
{in: native_, out: native_} {
e_res.bcx.build.PointerCast(e_res.val, ll_t_out)
}
_ {
ccx.sess.bug("Translating unsupported cast.");
C_nil() // FIXME the typechecker doesn't seem to understand _|_ here
}
};
ret rslt(e_res.bcx, newval);
}
fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty,

View file

@ -456,7 +456,6 @@ fn T_int() -> TypeRef {
fn T_float() -> TypeRef {
// FIXME: switch on target type.
ret T_f64();
}

View file

@ -1158,6 +1158,7 @@ fn type_is_integral(&ctxt cx, &t ty) -> bool {
}
}
case (ty_char) { ret true; }
case (ty_bool) { ret true; }
case (_) { ret false; }
}
}