|
11 | 11 | #![allow(non_upper_case_globals)]
|
12 | 12 |
|
13 | 13 | use llvm;
|
14 |
| -use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef}; |
| 14 | +use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind}; |
15 | 15 | use middle::subst;
|
16 | 16 | use middle::subst::FnSpace;
|
17 | 17 | use trans::base::*;
|
@@ -174,12 +174,65 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
174 | 174 | // This should be caught by the intrinsicck pass
|
175 | 175 | assert_eq!(in_type_size, out_type_size);
|
176 | 176 |
|
177 |
| - // We need to cast the dest so the types work out |
178 |
| - let dest = match dest { |
179 |
| - expr::SaveIn(d) => expr::SaveIn(PointerCast(bcx, d, llintype.ptr_to())), |
180 |
| - expr::Ignore => expr::Ignore |
| 177 | + let nonpointer_nonaggregate = |llkind: TypeKind| -> bool { |
| 178 | + use llvm::TypeKind::*; |
| 179 | + match llkind { |
| 180 | + Half | Float | Double | X86_FP80 | FP128 | |
| 181 | + PPC_FP128 | Integer | Vector | X86_MMX => true, |
| 182 | + _ => false |
| 183 | + } |
| 184 | + }; |
| 185 | + |
| 186 | + // An approximation to which types can be directly cast via |
| 187 | + // LLVM's bitcast. This doesn't cover pointer -> pointer casts, |
| 188 | + // but does, importantly, cover SIMD types. |
| 189 | + let in_kind = llintype.kind(); |
| 190 | + let ret_kind = llret_ty.kind(); |
| 191 | + let bitcast_compatible = |
| 192 | + (nonpointer_nonaggregate(in_kind) && nonpointer_nonaggregate(ret_kind)) || { |
| 193 | + in_kind == TypeKind::Pointer && ret_kind == TypeKind::Pointer |
| 194 | + }; |
| 195 | + |
| 196 | + let dest = if bitcast_compatible { |
| 197 | + // if we're here, the type is scalar-like (a primitive, a |
| 198 | + // SIMD type or a pointer), and so can be handled as a |
| 199 | + // by-value ValueRef and can also be directly bitcast to the |
| 200 | + // target type. Doing this special case makes conversions |
| 201 | + // like `u32x4` -> `u64x2` much nicer for LLVM and so more |
| 202 | + // efficient (these are done efficiently implicitly in C |
| 203 | + // with the `__m128i` type and so this means Rust doesn't |
| 204 | + // lose out there). |
| 205 | + let expr = &*arg_exprs[0]; |
| 206 | + let datum = unpack_datum!(bcx, expr::trans(bcx, expr)); |
| 207 | + let datum = unpack_datum!(bcx, datum.to_rvalue_datum(bcx, "transmute_temp")); |
| 208 | + let val = if datum.kind.is_by_ref() { |
| 209 | + load_ty(bcx, datum.val, datum.ty) |
| 210 | + } else { |
| 211 | + datum.val |
| 212 | + }; |
| 213 | + |
| 214 | + let cast_val = BitCast(bcx, val, llret_ty); |
| 215 | + |
| 216 | + match dest { |
| 217 | + expr::SaveIn(d) => { |
| 218 | + // this often occurs in a sequence like `Store(val, |
| 219 | + // d); val2 = Load(d)`, so disappears easily. |
| 220 | + Store(bcx, cast_val, d); |
| 221 | + } |
| 222 | + expr::Ignore => {} |
| 223 | + } |
| 224 | + dest |
| 225 | + } else { |
| 226 | + // The types are too complicated to do with a by-value |
| 227 | + // bitcast, so pointer cast instead. We need to cast the |
| 228 | + // dest so the types work out. |
| 229 | + let dest = match dest { |
| 230 | + expr::SaveIn(d) => expr::SaveIn(PointerCast(bcx, d, llintype.ptr_to())), |
| 231 | + expr::Ignore => expr::Ignore |
| 232 | + }; |
| 233 | + bcx = expr::trans_into(bcx, &*arg_exprs[0], dest); |
| 234 | + dest |
181 | 235 | };
|
182 |
| - bcx = expr::trans_into(bcx, &*arg_exprs[0], dest); |
183 | 236 |
|
184 | 237 | fcx.pop_custom_cleanup_scope(cleanup_scope);
|
185 | 238 |
|
|
0 commit comments