diff --git a/gen/abi-win64.cpp b/gen/abi-win64.cpp
index 3373d8f4d7f..4eced1a4eb2 100644
--- a/gen/abi-win64.cpp
+++ b/gen/abi-win64.cpp
@@ -36,14 +36,29 @@
 static bool canRewriteAsInt(Type* t)
 {
     unsigned size = t->size();
-    return size <= 8 &&
-           (size == 1 || size == 2 || size == 4 || size == 8) &&
-           (t->ty == Tstruct || t->ty == Tsarray);
+    return size == 1 || size == 2 || size == 4 || size == 8;
+}
+
+// Returns true if the D type is a composite (struct or static array).
+static bool isComposite(const Type* t)
+{
+    return t->ty == Tstruct || t->ty == Tsarray;
+}
 
+// Returns true if the D type is passed byval (the callee getting a pointer
+// to a dedicated hidden copy).
+static bool isPassedWithByvalSemantics(Type* t)
+{
+    return
+        // * structs and static arrays which can NOT be rewritten as integers
+        (isComposite(t) && !canRewriteAsInt(t)) ||
+        // * 80-bit real and ireal
+        (t->ty == Tfloat80 || t->ty == Timaginary80) ||
+        // * cdouble and creal
+        (t->ty == Tcomplex64 || t->ty == Tcomplex80);
 }
 
 // FIXME: This should actually be handled by LLVM and the ByVal arg attribute.
-// Implements byval argument passing for scalar non-struct types.
 struct Win64_byval_rewrite : ABIRewrite
 {
     // Get instance from pointer.
@@ -60,8 +75,9 @@ struct Win64_byval_rewrite : ABIRewrite
         DtoStore(DtoLoad(ptr), lval); // *lval = *ptr
     }
 
-    // Turn an instance into a pointer (to a private copy for the callee,
-    // allocated by the caller).
+    // Convert the caller's instance to a pointer for the callee.
+    // The pointer points to a dedicated copy for the callee which
+    // is allocated by the caller.
     LLValue* put(Type* dty, DValue* v)
     {
         /* NOTE: probably not safe
@@ -71,12 +87,25 @@ struct Win64_byval_rewrite : ABIRewrite
         */
 
         LLValue* original = v->getRVal();
-        LLValue* copy = DtoRawAlloca(original->getType(), 16, "copy_for_callee");
-        DtoStore(original, copy); // *copy = *original
+        LLValue* copy;
+
+        llvm::Type* type = original->getType();
+        if (type->isPointerTy())
+        {
+            type = type->getPointerElementType();
+            copy = DtoRawAlloca(type, 16, "copy_for_callee");
+            DtoStore(DtoLoad(original), copy); // *copy = *original
+        }
+        else
+        {
+            copy = DtoRawAlloca(type, 16, "copy_for_callee");
+            DtoStore(original, copy);          // *copy = original
+        }
+
         return copy;
     }
 
-    /// should return the transformed type for this rewrite
+    // T => T*
     LLType* type(Type* dty, LLType* t)
     {
         return getPtrToType(DtoType(dty));
@@ -134,22 +163,17 @@ bool Win64TargetABI::returnInArg(TypeFunction* tf)
     // everything <= 64 bits and of a size that is a power of 2
     // is returned in a register (RAX, or XMM0 for single float/
     // double) - except for cfloat
-    // real/ireal is returned on top of the x87 stack: ST(0)
+    // 80-bit real/ireal is returned on top of the x87 stack: ST(0)
     // complex numbers are returned in XMM0 & XMM1 (cfloat, cdouble)
     // or ST(1) & ST(0) (creal)
     // all other structs and static arrays are returned by struct-return (sret)
-    return (rt->ty == Tstruct
-            || rt->ty == Tsarray
-           ) && !canRewriteAsInt(rt);
+    return isComposite(rt) && !canRewriteAsInt(rt);
 }
 
 bool Win64TargetABI::passByVal(Type* t)
 {
     t = t->toBasetype();
-
-    // structs and static arrays are passed byval unless they can be
-    // rewritten as integers
-    return (t->ty == Tstruct || t->ty == Tsarray) && !canRewriteAsInt(t);
+    return isPassedWithByvalSemantics(t);
 }
 
 void Win64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
@@ -168,7 +192,7 @@ void Win64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
             // the other complex number types are returned via XMM0 = re and XMM1 = im
             fty.ret->rewrite = &swapComplex;
         }
-        else if (canRewriteAsInt(rt))
+        else if (isComposite(rt) && canRewriteAsInt(rt))
         {
             fty.ret->rewrite = &compositeToInt;
             fty.ret->ltype = compositeToInt.type(fty.ret->type, fty.ret->ltype);
@@ -195,12 +219,13 @@ void Win64TargetABI::rewriteFunctionType(TypeFunction* tf, IrFuncTy &fty)
             arg.rewrite = &cfloatToInt;
             arg.ltype = cfloatToInt.type(arg.type, arg.ltype);
         }
-        else if (canRewriteAsInt(ty))
+        else if (isComposite(ty) && canRewriteAsInt(ty))
         {
             arg.rewrite = &compositeToInt;
             arg.ltype = compositeToInt.type(arg.type, arg.ltype);
         }
-        else if (ty->iscomplex() || ty->ty == Tfloat80 || ty->ty == Timaginary80)
+        // FIXME: this should actually be handled by LLVM and the ByVal arg attribute
+        else if (isPassedWithByvalSemantics(ty))
         {
             // these types are passed byval:
             // the caller allocates a copy and then passes a pointer to the copy