about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-07-22 13:10:59 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-07-22 13:10:59 +0200
commitb45d973552c116b90185add4ddb5e4d32bb5cb9b (patch)
tree0c25314fbaae708373f61a7a176b5bc6ca0114be
parent5864d4e13aa6280eb1a7652990d2b7e08770e83f (diff)
downloadrust-b45d973552c116b90185add4ddb5e4d32bb5cb9b.tar.gz
rust-b45d973552c116b90185add4ddb5e4d32bb5cb9b.zip
Rewrite trans_cast, float->float and float->int casts
-rw-r--r--src/comp/lib/llvm.rs10
-rw-r--r--src/comp/middle/trans.rs111
-rw-r--r--src/comp/middle/trans_common.rs1
-rw-r--r--src/comp/middle/ty.rs1
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; }
     }
 }