@@ -6,7 +6,7 @@ use libc::{c_char, c_uint};
6
6
use rustc_abi as abi;
7
7
use rustc_abi:: { AddressSpace , Align , HasDataLayout , Size , TargetDataLayout , WrappingRange } ;
8
8
use rustc_codegen_ssa:: MemFlags ;
9
- use rustc_codegen_ssa:: common:: { IntPredicate , RealPredicate , TypeKind , AtomicRmwBinOp } ;
9
+ use rustc_codegen_ssa:: common:: { AtomicRmwBinOp , IntPredicate , RealPredicate , TypeKind } ;
10
10
use rustc_codegen_ssa:: mir:: operand:: { OperandRef , OperandValue } ;
11
11
use rustc_codegen_ssa:: mir:: place:: PlaceRef ;
12
12
use rustc_codegen_ssa:: traits:: * ;
@@ -1114,46 +1114,54 @@ impl<'ll, 'tcx, 'a> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
1114
1114
weak : bool ,
1115
1115
) -> ( & ' ll Value , & ' ll Value ) {
1116
1116
// LLVM verifier rejects cases where the `failure_order` is stronger than `order`
1117
- match ( order, failure_order) {
1118
- ( AtomicOrdering :: SeqCst , _) =>( ) ,
1119
- ( _, AtomicOrdering :: Relaxed ) =>( ) ,
1120
- ( AtomicOrdering :: Release , AtomicOrdering :: Release ) | ( AtomicOrdering :: Release , AtomicOrdering :: Acquire ) | ( AtomicOrdering :: Acquire , AtomicOrdering :: Acquire ) =>( ) ,
1121
- ( AtomicOrdering :: AcqRel , AtomicOrdering :: Acquire ) => ( ) ,
1122
- ( AtomicOrdering :: Relaxed , _) | ( _, AtomicOrdering :: Release | AtomicOrdering :: AcqRel | AtomicOrdering :: SeqCst ) =>{
1117
+ match ( order, failure_order) {
1118
+ ( AtomicOrdering :: SeqCst , _) => ( ) ,
1119
+ ( _, AtomicOrdering :: Relaxed ) => ( ) ,
1120
+ ( AtomicOrdering :: Release , AtomicOrdering :: Release )
1121
+ | ( AtomicOrdering :: Release , AtomicOrdering :: Acquire )
1122
+ | ( AtomicOrdering :: Acquire , AtomicOrdering :: Acquire ) => ( ) ,
1123
+ ( AtomicOrdering :: AcqRel , AtomicOrdering :: Acquire ) => ( ) ,
1124
+ ( AtomicOrdering :: Relaxed , _)
1125
+ | ( _, AtomicOrdering :: Release | AtomicOrdering :: AcqRel | AtomicOrdering :: SeqCst ) => {
1123
1126
// Invalid cmpxchg - `failure_order` is stronger than `order`! So, we abort.
1124
1127
self . abort ( ) ;
1125
- return ( self . const_undef ( self . val_ty ( cmp) ) , self . const_undef ( self . type_i1 ( ) ) ) ;
1128
+ return (
1129
+ self . const_undef ( self . val_ty ( cmp) ) ,
1130
+ self . const_undef ( self . type_i1 ( ) ) ,
1131
+ ) ;
1126
1132
}
1127
1133
} ;
1128
1134
let res = self . atomic_op (
1129
1135
dst,
1130
- |builder, dst| {
1136
+ |builder, dst| {
1131
1137
// We are in a supported address space - just use ordinary atomics
1132
1138
unsafe {
1133
1139
llvm:: LLVMRustBuildAtomicCmpXchg (
1134
1140
builder. llbuilder ,
1135
1141
dst,
1136
1142
cmp,
1137
1143
src,
1138
- crate :: llvm:: AtomicOrdering :: from_generic ( order) ,
1144
+ crate :: llvm:: AtomicOrdering :: from_generic ( order) ,
1139
1145
crate :: llvm:: AtomicOrdering :: from_generic ( failure_order) ,
1140
1146
weak as u32 ,
1141
1147
)
1142
1148
}
1143
1149
} ,
1144
- |builder, dst| {
1150
+ |builder, dst| {
1145
1151
// Local space is only accessible to the current thread.
1146
- // So, there are no synchronization issues, and we can emulate it using a simple load / compare / store.
1147
- let load: & ' ll Value = unsafe { llvm:: LLVMBuildLoad ( builder. llbuilder , dst, UNNAMED ) } ;
1152
+ // So, there are no synchronization issues, and we can emulate it using a simple load / compare / store.
1153
+ let load: & ' ll Value =
1154
+ unsafe { llvm:: LLVMBuildLoad ( builder. llbuilder , dst, UNNAMED ) } ;
1148
1155
let compare = builder. icmp ( IntPredicate :: IntEQ , load, cmp) ;
1149
1156
// We can do something smart & branchless here:
1150
- // We select either the current value(if the comparison fails), or a new value.
1157
+ // We select either the current value(if the comparison fails), or a new value.
1151
1158
// We then *undconditionally* write that back to local memory(which is very, very cheap).
1152
1159
// TODO: measure if this has a positive impact, or if we should just use more blocks, and conditional writes.
1153
1160
let value = builder. select ( compare, src, load) ;
1154
- unsafe { llvm:: LLVMBuildStore ( builder. llbuilder , value, dst) } ;
1155
- let res_type = builder. type_struct ( & [ builder. val_ty ( cmp) , builder. type_ix ( 1 ) ] , false ) ;
1156
- // We pack the result, to match the behaviour of proper atomics / emulated thread-local atomics.
1161
+ unsafe { llvm:: LLVMBuildStore ( builder. llbuilder , value, dst) } ;
1162
+ let res_type =
1163
+ builder. type_struct ( & [ builder. val_ty ( cmp) , builder. type_ix ( 1 ) ] , false ) ;
1164
+ // We pack the result, to match the behaviour of proper atomics / emulated thread-local atomics.
1157
1165
let res = builder. const_undef ( res_type) ;
1158
1166
let res = builder. insert_value ( res, load, 0 ) ;
1159
1167
let res = builder. insert_value ( res, compare, 1 ) ;
@@ -1172,57 +1180,58 @@ impl<'ll, 'tcx, 'a> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
1172
1180
src : & ' ll Value ,
1173
1181
order : AtomicOrdering ,
1174
1182
) -> & ' ll Value {
1175
- if matches ! ( op, AtomicRmwBinOp :: AtomicNand ) {
1183
+ if matches ! ( op, AtomicRmwBinOp :: AtomicNand ) {
1176
1184
self . fatal ( "Atomic NAND not supported yet!" )
1177
1185
}
1178
1186
self . atomic_op (
1179
1187
dst,
1180
- |builder, dst| {
1188
+ |builder, dst| {
1181
1189
// We are in a supported address space - just use ordinary atomics
1182
1190
unsafe {
1183
1191
llvm:: LLVMBuildAtomicRMW (
1184
1192
builder. llbuilder ,
1185
1193
op,
1186
1194
dst,
1187
1195
src,
1188
- crate :: llvm:: AtomicOrdering :: from_generic ( order) ,
1196
+ crate :: llvm:: AtomicOrdering :: from_generic ( order) ,
1189
1197
0 ,
1190
1198
)
1191
1199
}
1192
1200
} ,
1193
- |builder, dst| {
1201
+ |builder, dst| {
1194
1202
// Local space is only accessible to the current thread.
1195
- // So, there are no synchronization issues, and we can emulate it using a simple load / compare / store.
1196
- let load: & ' ll Value = unsafe { llvm:: LLVMBuildLoad ( builder. llbuilder , dst, UNNAMED ) } ;
1197
- let next_val = match op{
1203
+ // So, there are no synchronization issues, and we can emulate it using a simple load / compare / store.
1204
+ let load: & ' ll Value =
1205
+ unsafe { llvm:: LLVMBuildLoad ( builder. llbuilder , dst, UNNAMED ) } ;
1206
+ let next_val = match op {
1198
1207
AtomicRmwBinOp :: AtomicXchg => src,
1199
1208
AtomicRmwBinOp :: AtomicAdd => builder. add ( load, src) ,
1200
1209
AtomicRmwBinOp :: AtomicSub => builder. sub ( load, src) ,
1201
1210
AtomicRmwBinOp :: AtomicAnd => builder. and ( load, src) ,
1202
1211
AtomicRmwBinOp :: AtomicNand => {
1203
1212
let and = builder. and ( load, src) ;
1204
1213
builder. not ( and)
1205
- } ,
1214
+ }
1206
1215
AtomicRmwBinOp :: AtomicOr => builder. or ( load, src) ,
1207
1216
AtomicRmwBinOp :: AtomicXor => builder. xor ( load, src) ,
1208
1217
AtomicRmwBinOp :: AtomicMax => {
1209
1218
let is_src_bigger = builder. icmp ( IntPredicate :: IntSGT , src, load) ;
1210
- builder. select ( is_src_bigger, src, load)
1219
+ builder. select ( is_src_bigger, src, load)
1211
1220
}
1212
1221
AtomicRmwBinOp :: AtomicMin => {
1213
1222
let is_src_smaller = builder. icmp ( IntPredicate :: IntSLT , src, load) ;
1214
- builder. select ( is_src_smaller, src, load)
1223
+ builder. select ( is_src_smaller, src, load)
1215
1224
}
1216
- AtomicRmwBinOp :: AtomicUMax => {
1225
+ AtomicRmwBinOp :: AtomicUMax => {
1217
1226
let is_src_bigger = builder. icmp ( IntPredicate :: IntUGT , src, load) ;
1218
- builder. select ( is_src_bigger, src, load)
1219
- } ,
1227
+ builder. select ( is_src_bigger, src, load)
1228
+ }
1220
1229
AtomicRmwBinOp :: AtomicUMin => {
1221
1230
let is_src_smaller = builder. icmp ( IntPredicate :: IntULT , src, load) ;
1222
- builder. select ( is_src_smaller, src, load)
1231
+ builder. select ( is_src_smaller, src, load)
1223
1232
}
1224
1233
} ;
1225
- unsafe { llvm:: LLVMBuildStore ( builder. llbuilder , next_val, dst) } ;
1234
+ unsafe { llvm:: LLVMBuildStore ( builder. llbuilder , next_val, dst) } ;
1226
1235
load
1227
1236
} ,
1228
1237
)
@@ -1687,8 +1696,8 @@ impl<'ll, 'tcx, 'a> Builder<'a, 'll, 'tcx> {
1687
1696
fn atomic_op (
1688
1697
& mut self ,
1689
1698
dst : & ' ll Value ,
1690
- atomic_supported : impl FnOnce ( & mut Builder < ' a , ' ll , ' tcx > , & ' ll Value ) -> & ' ll Value ,
1691
- emulate_local : impl FnOnce ( & mut Builder < ' a , ' ll , ' tcx > , & ' ll Value ) -> & ' ll Value ,
1699
+ atomic_supported : impl FnOnce ( & mut Builder < ' a , ' ll , ' tcx > , & ' ll Value ) -> & ' ll Value ,
1700
+ emulate_local : impl FnOnce ( & mut Builder < ' a , ' ll , ' tcx > , & ' ll Value ) -> & ' ll Value ,
1692
1701
) -> & ' ll Value {
1693
1702
// (FractalFir) Atomics in CUDA have some limitations, and we have to work around them.
1694
1703
// For example, they are restricted in what address space they operate on.
0 commit comments