Skip to content

Commit 9c0b97d

Browse files
committed
Fix and improve translation of transmute
My earlier changes caused the result to be incorrect when both the input and output types were immediate. This has been fixed. I also extended the code to handle int -> ptr and ptr -> int casts as simple cases, since it's fairly easy to do. I changed the one place that was transmuting a function pointer to an integer to just use a cast, it's more clear this way.
1 parent 7ec6f7b commit 9c0b97d

File tree

3 files changed

+50
-16
lines changed

3 files changed

+50
-16
lines changed

src/librustc_trans/trans/expr.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,9 @@ fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
596596
fty.abi == synabi::RustIntrinsic;
597597

598598
let needs_drop = type_needs_drop(bcx.tcx(), ret_ty);
599+
let uses_output = type_of::return_uses_outptr(bcx.ccx(), ret_ty);
599600

600-
if is_rust_fn && type_is_immediate(bcx.ccx(), ret_ty) && !needs_drop {
601+
if is_rust_fn && !uses_output && !needs_drop {
601602
let args = callee::ArgExprs(&args[..]);
602603
let result = callee::trans_call_inner(bcx,
603604
expr.debug_loc(),

src/librustc_trans/trans/intrinsic.rs

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
171171
let foreign_item = tcx.map.expect_foreign_item(node);
172172
let name = token::get_ident(foreign_item.ident);
173173

174+
let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
175+
174176
// For `transmute` we can just trans the input expr directly into dest
175177
if &name[..] == "transmute" {
176178
let llret_ty = type_of::type_of(ccx, ret_ty.unwrap());
@@ -199,14 +201,14 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
199201
};
200202

201203
// An approximation to which types can be directly cast via
202-
// LLVM's bitcast. This doesn't cover pointer -> pointer casts,
203-
// but does, importantly, cover SIMD types.
204+
// LLVM's bitcast.
204205
let in_kind = llintype.kind();
205206
let ret_kind = llret_ty.kind();
206207
let bitcast_compatible =
207-
(nonpointer_nonaggregate(in_kind) && nonpointer_nonaggregate(ret_kind)) || {
208-
in_kind == TypeKind::Pointer && ret_kind == TypeKind::Pointer
209-
};
208+
(nonpointer_nonaggregate(in_kind) && nonpointer_nonaggregate(ret_kind)) ||
209+
(in_kind == TypeKind::Pointer && ret_kind == TypeKind::Pointer) ||
210+
(in_kind == TypeKind::Pointer && ret_kind == TypeKind::Integer) ||
211+
(in_kind == TypeKind::Integer && ret_kind == TypeKind::Pointer);
210212

211213
let val = if bitcast_compatible {
212214
// if we're here, the type is scalar-like (a primitive, a
@@ -226,29 +228,62 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
226228
from_arg_ty(bcx, datum.val, datum.ty)
227229
};
228230

229-
let cast_val = BitCast(bcx, val, llret_ty);
231+
// Do the appropriate cast type
232+
let cast_val = match (in_kind, ret_kind) {
233+
(TypeKind::Pointer, TypeKind::Pointer) => PointerCast(bcx, val, llret_ty),
234+
(TypeKind::Pointer, TypeKind::Integer) => PtrToInt(bcx, val, llret_ty),
235+
(TypeKind::Integer, TypeKind::Pointer) => IntToPtr(bcx, val, llret_ty),
236+
_ => BitCast(bcx, val, llret_ty)
237+
};
230238

231239
match dest {
232240
expr::SaveIn(d) => {
233241
// this often occurs in a sequence like `Store(val,
234242
// d); val2 = Load(d)`, so disappears easily.
235243
Store(bcx, cast_val, d);
236-
d
237244
}
238-
expr::Ignore => { cast_val }
245+
expr::Ignore => {}
239246
}
247+
cast_val
240248
} else {
241249
// The types are too complicated to do with a by-value
242250
// bitcast, so pointer cast instead. We need to cast the
243251
// dest so the types work out.
244-
let dest = match dest {
252+
253+
// Create the destination, if we were passed a destination, bitcast it to the
254+
// appropriate type. Otherwise, create a temporary destination for immediate
255+
// types and just ignore non-immediate types. This is because we return the
256+
// result for immediate values.
257+
let tmp_dest = match dest {
245258
expr::SaveIn(d) => expr::SaveIn(PointerCast(bcx, d, llintype.ptr_to())),
246-
expr::Ignore => expr::Ignore
259+
expr::Ignore => if type_is_immediate(bcx.ccx(), out_type) {
260+
expr::SaveIn(alloc_ty(bcx, in_type, "intrinsic_result"))
261+
} else {
262+
expr::Ignore
263+
}
247264
};
248-
bcx = expr::trans_into(bcx, &*arg_exprs[0], dest);
265+
bcx = expr::trans_into(bcx, &*arg_exprs[0], tmp_dest);
249266
match dest {
250267
expr::SaveIn(d) => d,
251-
expr::Ignore => C_undef(llret_ty)
268+
expr::Ignore => {
269+
// We weren't passed a destination to save to, if we made a temporary
270+
// destination, load the immediate value stored and clean up the type.
271+
// Otherwise return ().
272+
if let expr::SaveIn(d) = tmp_dest {
273+
let val = if type_is_immediate(bcx.ccx(), out_type) {
274+
let d = PointerCast(bcx, d, llouttype.ptr_to());
275+
load_ty(bcx, d, out_type)
276+
} else {
277+
C_nil(bcx.ccx())
278+
};
279+
280+
bcx = glue::drop_ty(bcx, d, out_type, call_debug_location);
281+
282+
val
283+
} else {
284+
C_nil(bcx.ccx())
285+
}
286+
}
252287
}
253288
};
254289

@@ -320,8 +355,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
320355

321356
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
322357

323-
let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
324-
325358
// These are the only intrinsic functions that diverge.
326359
if &name[..] == "abort" {
327360
let llfn = ccx.get_intrinsic(&("llvm.trap"));

src/libstd/rt/unwind/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ pub unsafe fn register(f: Callback) -> bool {
306306
// been incremented, but the callback has not been stored. We're
307307
// guaranteed that the slot we're storing into is 0.
308308
n if n < MAX_CALLBACKS => {
309-
let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst);
309+
let prev = CALLBACKS[n].swap(f as usize, Ordering::SeqCst);
310310
rtassert!(prev == 0);
311311
true
312312
}

0 commit comments

Comments
 (0)