From 659be55daa7644777e5379a127543942d3dc954d Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Tue, 25 Nov 2014 23:44:32 +0000 Subject: [PATCH] CodeGen: Fix emission of __atomic_compare_exchange We (wrongly) discarded the return value of the call. llvm-svn: 222798 --- clang/lib/CodeGen/CGAtomic.cpp | 44 ++++++++++++++++++++--------------------- clang/test/CodeGen/atomic-ops.c | 13 ++++++++++-- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index c83ae13..f492a06 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -588,8 +588,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { 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) { @@ -729,32 +732,29 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { } 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()); } @@ -767,7 +767,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { 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()); diff --git a/clang/test/CodeGen/atomic-ops.c b/clang/test/CodeGen/atomic-ops.c index 08731aa..576e401 100644 --- a/clang/test/CodeGen/atomic-ops.c +++ b/clang/test/CodeGen/atomic-ops.c @@ -383,14 +383,23 @@ struct foo structAtomicExchange() { } 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 -- 2.7.4