break;
}
- if (!E->getType()->isVoidType() && !Dest)
- Dest = CreateMemTemp(E->getType(), ".atomicdst");
+ auto GetDest = [&] {
+ if (!E->getType()->isVoidType() && !Dest)
+ Dest = CreateMemTemp(E->getType(), ".atomicdst");
+ return Dest;
+ };
// Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
if (UseLibcall) {
} else {
// Value is returned through parameter before the order.
RetTy = getContext().VoidTy;
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)), getContext().VoidPtrTy);
}
}
// order is always the last parameter
Args.add(RValue::get(Order),
getContext().IntTy);
- const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeFreeFunctionCall(RetTy, Args,
- FunctionType::ExtInfo(), RequiredArgs::All);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
- llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
- RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
- if (!RetTy->isVoidType()) {
- if (UseOptimizedLibcall) {
- if (HaveRetTy)
- return Res;
- llvm::StoreInst *StoreDest = Builder.CreateStore(
- Res.getScalarVal(),
- Builder.CreateBitCast(Dest, FTy->getReturnType()->getPointerTo()));
- StoreDest->setAlignment(Align);
- }
- }
- if (E->getType()->isVoidType())
+ RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args);
+ // The value is returned directly from the libcall.
+ if (HaveRetTy && !RetTy->isVoidType())
+ return Res;
+ // The value is returned via an explicit out param.
+ if (RetTy->isVoidType())
return RValue::get(nullptr);
+ // The value is returned directly for optimized libcalls but the caller is
+ // expected an out-param.
+ if (UseOptimizedLibcall) {
+ llvm::Value *ResVal = Res.getScalarVal();
+ llvm::StoreInst *StoreDest = Builder.CreateStore(
+ ResVal,
+ Builder.CreateBitCast(GetDest(), ResVal->getType()->getPointerTo()));
+ StoreDest->setAlignment(Align);
+ }
return convertTempToRValue(Dest, E->getType(), E->getExprLoc());
}
llvm::Type *ITy =
llvm::IntegerType::get(getLLVMContext(), Size * 8);
- llvm::Value *OrigDest = Dest;
+ llvm::Value *OrigDest = GetDest();
Ptr = Builder.CreateBitCast(
Ptr, ITy->getPointerTo(Ptr->getType()->getPointerAddressSpace()));
if (Val1) Val1 = Builder.CreateBitCast(Val1, ITy->getPointerTo());
}
int structAtomicCmpExchange() {
// CHECK-LABEL: @structAtomicCmpExchange
+ // CHECK: %[[x_mem:.*]] = alloca i8
_Bool x = __atomic_compare_exchange(&smallThing, &thing1, &thing2, 1, 5, 5);
- // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 3, {{.*}} @smallThing{{.*}} @thing1{{.*}} @thing2
+ // CHECK: %[[call1:.*]] = call zeroext i1 @__atomic_compare_exchange(i32 3, {{.*}} @smallThing{{.*}} @thing1{{.*}} @thing2
+ // CHECK: %[[zext1:.*]] = zext i1 %[[call1]] to i8
+ // CHECK: store i8 %[[zext1]], i8* %[[x_mem]], align 1
+ // CHECK: %[[x:.*]] = load i8* %[[x_mem]]
+ // CHECK: %[[x_bool:.*]] = trunc i8 %[[x]] to i1
+ // CHECK: %[[conv1:.*]] = zext i1 %[[x_bool]] to i32
struct foo f = {0};
struct foo g = {0};
g.big[12] = 12;
return x & __c11_atomic_compare_exchange_strong(&bigAtomic, &f, g, 5, 5);
- // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+ // CHECK: %[[call2:.*]] = call zeroext i1 @__atomic_compare_exchange(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*),
+ // CHECK: %[[conv2:.*]] = zext i1 %[[call2]] to i32
+ // CHECK: %[[and:.*]] = and i32 %[[conv1]], %[[conv2]]
+ // CHECK: ret i32 %[[and]]
}
// Check that no atomic operations are used in any initialisation of _Atomic