r222798 - CodeGen: Fix emission of __atomic_compare_exchange

David Majnemer david.majnemer at gmail.com
Tue Nov 25 15:44:33 PST 2014


Author: majnemer
Date: Tue Nov 25 17:44:32 2014
New Revision: 222798

URL: http://llvm.org/viewvc/llvm-project?rev=222798&view=rev
Log:
CodeGen: Fix emission of __atomic_compare_exchange

We (wrongly) discarded the return value of the call.

Modified:
    cfe/trunk/lib/CodeGen/CGAtomic.cpp
    cfe/trunk/test/CodeGen/atomic-ops.c

Modified: cfe/trunk/lib/CodeGen/CGAtomic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGAtomic.cpp?rev=222798&r1=222797&r2=222798&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGAtomic.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGAtomic.cpp Tue Nov 25 17:44:32 2014
@@ -588,8 +588,11 @@ RValue CodeGenFunction::EmitAtomicExpr(A
     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(A
       } 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(A
 
   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());

Modified: cfe/trunk/test/CodeGen/atomic-ops.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/atomic-ops.c?rev=222798&r1=222797&r2=222798&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/atomic-ops.c (original)
+++ cfe/trunk/test/CodeGen/atomic-ops.c Tue Nov 25 17:44:32 2014
@@ -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





More information about the cfe-commits mailing list