Skip to content

Commit d4ca1cf

Browse files
committed
Fix volatile / atomic ops on bools and small aggregates
Boolean values and small aggregates have a different type in args/allocas than in SSA values but the intrinsics for volatile and atomic ops were missing the necessary casts to handle that. Fixes #23550
1 parent ecdf792 commit d4ca1cf

File tree

3 files changed

+116
-45
lines changed

3 files changed

+116
-45
lines changed

src/librustc_trans/trans/base.rs

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -983,56 +983,72 @@ pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
983983
/// gives us better information about what we are loading.
984984
pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
985985
ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
986-
if type_is_zero_size(cx.ccx(), t) {
987-
C_undef(type_of::type_of(cx.ccx(), t))
988-
} else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
989-
// We want to pass small aggregates as immediate values, but using an aggregate LLVM type
990-
// for this leads to bad optimizations, so its arg type is an appropriately sized integer
991-
// and we have to convert it
992-
Load(cx, BitCast(cx, ptr, type_of::arg_type_of(cx.ccx(), t).ptr_to()))
993-
} else {
994-
unsafe {
995-
let global = llvm::LLVMIsAGlobalVariable(ptr);
996-
if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
997-
let val = llvm::LLVMGetInitializer(global);
998-
if !val.is_null() {
999-
// This could go into its own function, for DRY.
1000-
// (something like "pre-store packing/post-load unpacking")
1001-
if ty::type_is_bool(t) {
1002-
return Trunc(cx, val, Type::i1(cx.ccx()));
1003-
} else {
1004-
return val;
1005-
}
1006-
}
986+
if cx.unreachable.get() || type_is_zero_size(cx.ccx(), t) {
987+
return C_undef(type_of::type_of(cx.ccx(), t));
988+
}
989+
990+
let ptr = to_arg_ty_ptr(cx, ptr, t);
991+
992+
if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
993+
return Load(cx, ptr);
994+
}
995+
996+
unsafe {
997+
let global = llvm::LLVMIsAGlobalVariable(ptr);
998+
if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
999+
let val = llvm::LLVMGetInitializer(global);
1000+
if !val.is_null() {
1001+
return from_arg_ty(cx, val, t);
10071002
}
10081003
}
1009-
if ty::type_is_bool(t) {
1010-
Trunc(cx, LoadRangeAssert(cx, ptr, 0, 2, llvm::False), Type::i1(cx.ccx()))
1011-
} else if ty::type_is_char(t) {
1012-
// a char is a Unicode codepoint, and so takes values from 0
1013-
// to 0x10FFFF inclusive only.
1014-
LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
1015-
} else if (ty::type_is_region_ptr(t) || ty::type_is_unique(t))
1016-
&& !common::type_is_fat_ptr(cx.tcx(), t) {
1017-
LoadNonNull(cx, ptr)
1018-
} else {
1019-
Load(cx, ptr)
1020-
}
10211004
}
1005+
1006+
let val = if ty::type_is_bool(t) {
1007+
LoadRangeAssert(cx, ptr, 0, 2, llvm::False)
1008+
} else if ty::type_is_char(t) {
1009+
// a char is a Unicode codepoint, and so takes values from 0
1010+
// to 0x10FFFF inclusive only.
1011+
LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
1012+
} else if (ty::type_is_region_ptr(t) || ty::type_is_unique(t))
1013+
&& !common::type_is_fat_ptr(cx.tcx(), t) {
1014+
LoadNonNull(cx, ptr)
1015+
} else {
1016+
Load(cx, ptr)
1017+
};
1018+
1019+
from_arg_ty(cx, val, t)
10221020
}
10231021

10241022
/// Helper for storing values in memory. Does the necessary conversion if the in-memory type
10251023
/// differs from the type used for SSA values.
10261024
pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
1027-
if ty::type_is_bool(t) {
1028-
Store(cx, ZExt(cx, v, Type::i8(cx.ccx())), dst);
1029-
} else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
1025+
Store(cx, to_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t));
1026+
}
1027+
1028+
pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
1029+
if ty::type_is_bool(ty) {
1030+
ZExt(bcx, val, Type::i8(bcx.ccx()))
1031+
} else {
1032+
val
1033+
}
1034+
}
1035+
1036+
pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
1037+
if ty::type_is_bool(ty) {
1038+
Trunc(bcx, val, Type::i1(bcx.ccx()))
1039+
} else {
1040+
val
1041+
}
1042+
}
1043+
1044+
pub fn to_arg_ty_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef, ty: Ty<'tcx>) -> ValueRef {
1045+
if type_is_immediate(bcx.ccx(), ty) && type_of::type_of(bcx.ccx(), ty).is_aggregate() {
10301046
// We want to pass small aggregates as immediate values, but using an aggregate LLVM type
10311047
// for this leads to bad optimizations, so its arg type is an appropriately sized integer
10321048
// and we have to convert it
1033-
Store(cx, v, BitCast(cx, dst, type_of::arg_type_of(cx.ccx(), t).ptr_to()));
1049+
BitCast(bcx, ptr, type_of::arg_type_of(bcx.ccx(), ty).ptr_to())
10341050
} else {
1035-
Store(cx, v, dst);
1051+
ptr
10361052
}
10371053
}
10381054

src/librustc_trans/trans/intrinsic.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -446,10 +446,15 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
446446
call_debug_location)
447447
}
448448
(_, "volatile_load") => {
449-
VolatileLoad(bcx, llargs[0])
449+
let tp_ty = *substs.types.get(FnSpace, 0);
450+
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
451+
from_arg_ty(bcx, VolatileLoad(bcx, ptr), tp_ty)
450452
},
451453
(_, "volatile_store") => {
452-
VolatileStore(bcx, llargs[1], llargs[0]);
454+
let tp_ty = *substs.types.get(FnSpace, 0);
455+
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
456+
let val = to_arg_ty(bcx, llargs[1], tp_ty);
457+
VolatileStore(bcx, val, ptr);
453458
C_nil(ccx)
454459
},
455460

@@ -709,8 +714,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
709714
llvm::SequentiallyConsistent
710715
};
711716

712-
let res = AtomicCmpXchg(bcx, llargs[0], llargs[1],
713-
llargs[2], order,
717+
let tp_ty = *substs.types.get(FnSpace, 0);
718+
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
719+
let cmp = to_arg_ty(bcx, llargs[1], tp_ty);
720+
let src = to_arg_ty(bcx, llargs[2], tp_ty);
721+
let res = AtomicCmpXchg(bcx, ptr, cmp, src, order,
714722
strongest_failure_ordering);
715723
if unsafe { llvm::LLVMVersionMinor() >= 5 } {
716724
ExtractValue(bcx, res, 0)
@@ -720,10 +728,15 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
720728
}
721729

722730
"load" => {
723-
AtomicLoad(bcx, llargs[0], order)
731+
let tp_ty = *substs.types.get(FnSpace, 0);
732+
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
733+
from_arg_ty(bcx, AtomicLoad(bcx, ptr, order), tp_ty)
724734
}
725735
"store" => {
726-
AtomicStore(bcx, llargs[1], llargs[0], order);
736+
let tp_ty = *substs.types.get(FnSpace, 0);
737+
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
738+
let val = to_arg_ty(bcx, llargs[1], tp_ty);
739+
AtomicStore(bcx, val, ptr, order);
727740
C_nil(ccx)
728741
}
729742

@@ -749,7 +762,10 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
749762
_ => ccx.sess().fatal("unknown atomic operation")
750763
};
751764

752-
AtomicRMW(bcx, atom_op, llargs[0], llargs[1], order)
765+
let tp_ty = *substs.types.get(FnSpace, 0);
766+
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
767+
let val = to_arg_ty(bcx, llargs[1], tp_ty);
768+
AtomicRMW(bcx, atom_op, ptr, val, order)
753769
}
754770
}
755771

src/test/run-pass/issue-23550.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(core)]
12+
#![allow(warnings)]
13+
14+
use std::intrinsics;
15+
16+
#[derive(Copy)]
17+
struct Wrap(i64);
18+
19+
// These volatile and atomic intrinsics used to cause an ICE
20+
21+
unsafe fn test_bool(p: &mut bool, v: bool) {
22+
intrinsics::volatile_load(p);
23+
intrinsics::volatile_store(p, v);
24+
intrinsics::atomic_load(p);
25+
intrinsics::atomic_cxchg(p, v, v);
26+
intrinsics::atomic_store(p, v);
27+
intrinsics::atomic_xchg(p, v);
28+
}
29+
30+
unsafe fn test_immediate_fca(p: &mut Wrap, v: Wrap) {
31+
intrinsics::volatile_load(p);
32+
intrinsics::volatile_store(p, v);
33+
intrinsics::atomic_load(p);
34+
intrinsics::atomic_cxchg(p, v, v);
35+
intrinsics::atomic_store(p, v);
36+
intrinsics::atomic_xchg(p, v);
37+
}
38+
39+
fn main() {}

0 commit comments

Comments
 (0)