diff options
| author | Marijn Haverbeke <marijnh@gmail.com> | 2011-07-22 13:10:59 +0200 |
|---|---|---|
| committer | Marijn Haverbeke <marijnh@gmail.com> | 2011-07-22 13:10:59 +0200 |
| commit | b45d973552c116b90185add4ddb5e4d32bb5cb9b (patch) | |
| tree | 0c25314fbaae708373f61a7a176b5bc6ca0114be | |
| parent | 5864d4e13aa6280eb1a7652990d2b7e08770e83f (diff) | |
| download | rust-b45d973552c116b90185add4ddb5e4d32bb5cb9b.tar.gz rust-b45d973552c116b90185add4ddb5e4d32bb5cb9b.zip | |
Rewrite trans_cast, float->float and float->int casts
| -rw-r--r-- | src/comp/lib/llvm.rs | 10 | ||||
| -rw-r--r-- | src/comp/middle/trans.rs | 111 | ||||
| -rw-r--r-- | src/comp/middle/trans_common.rs | 1 | ||||
| -rw-r--r-- | src/comp/middle/ty.rs | 1 |
4 files changed, 73 insertions, 50 deletions
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index bb7dd4f2621..f2260922c56 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -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)); diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 181ea12c2d5..47b5365d755 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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. - - ret bcx.build.SExtOrBitCast(llsrc, lldsttype); - } - // Widening unsigned 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.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)) { - - // 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))); - } - } - 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 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); + + 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 }; + } + 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, diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index 9f2014b2a2d..d5b926f482d 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -456,7 +456,6 @@ fn T_int() -> TypeRef { fn T_float() -> TypeRef { // FIXME: switch on target type. - ret T_f64(); } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 61e61579e67..d6f723f1ea5 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -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; } } } |
