r212175 - ARM: add support for v8 ldaex/stlex builtins.

Tim Northover tnorthover at apple.com
Wed Jul 2 05:56:03 PDT 2014


Author: tnorthover
Date: Wed Jul  2 07:56:02 2014
New Revision: 212175

URL: http://llvm.org/viewvc/llvm-project?rev=212175&view=rev
Log:
ARM: add support for v8 ldaex/stlex builtins.

ARMv8 adds (to both AArch32 and AArch64) acquiring and releasing
variants of the exclusive operations, in line with the C++11 memory
model.

This adds support for two new intrinsics to expose them to C & C++
developers directly: __builtin_arm_ldaex and __builtin_arm_stlex, in
direct analogy with the versions with no implicit barrier.

rdar://problem/15885451

Modified:
    cfe/trunk/docs/LanguageExtensions.rst
    cfe/trunk/include/clang/Basic/BuiltinsAArch64.def
    cfe/trunk/include/clang/Basic/BuiltinsARM.def
    cfe/trunk/lib/CodeGen/CGBuiltin.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/test/CodeGen/builtins-arm-exclusive.c
    cfe/trunk/test/Sema/builtins-arm-exclusive.c
    cfe/trunk/test/Sema/builtins-arm64-exclusive.c

Modified: cfe/trunk/docs/LanguageExtensions.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.rst?rev=212175&r1=212174&r2=212175&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.rst (original)
+++ cfe/trunk/docs/LanguageExtensions.rst Wed Jul  2 07:56:02 2014
@@ -1580,7 +1580,9 @@ instructions for implementing atomic ope
 .. code-block:: c
 
   T __builtin_arm_ldrex(const volatile T *addr);
+  T __builtin_arm_ldaex(const volatile T *addr);
   int __builtin_arm_strex(T val, volatile T *addr);
+  int __builtin_arm_stlex(T val, volatile T *addr);
   void __builtin_arm_clrex(void);
 
 The types ``T`` currently supported are:
@@ -1589,11 +1591,11 @@ The types ``T`` currently supported are:
 * Pointer types.
 
 Note that the compiler does not guarantee it will not insert stores which clear
-the exclusive monitor in between an ``ldrex`` and its paired ``strex``. In
-practice this is only usually a risk when the extra store is on the same cache
-line as the variable being modified and Clang will only insert stack stores on
-its own, so it is best not to use these operations on variables with automatic
-storage duration.
+the exclusive monitor in between an ``ldrex`` type operation and its paired
+``strex``. In practice this is only usually a risk when the extra store is on
+the same cache line as the variable being modified and Clang will only insert
+stack stores on its own, so it is best not to use these operations on variables
+with automatic storage duration.
 
 Also, loads and stores may be implicit in code written between the ``ldrex`` and
 ``strex``. Clang will not necessarily mitigate the effects of these either, so

Modified: cfe/trunk/include/clang/Basic/BuiltinsAArch64.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/BuiltinsAArch64.def?rev=212175&r1=212174&r2=212175&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/BuiltinsAArch64.def (original)
+++ cfe/trunk/include/clang/Basic/BuiltinsAArch64.def Wed Jul  2 07:56:02 2014
@@ -18,7 +18,9 @@
 BUILTIN(__clear_cache, "vv*v*", "i")
 
 BUILTIN(__builtin_arm_ldrex, "v.", "t")
+BUILTIN(__builtin_arm_ldaex, "v.", "t")
 BUILTIN(__builtin_arm_strex, "i.", "t")
+BUILTIN(__builtin_arm_stlex, "i.", "t")
 BUILTIN(__builtin_arm_clrex, "v", "")
 
 // Bit manipulation

Modified: cfe/trunk/include/clang/Basic/BuiltinsARM.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/BuiltinsARM.def?rev=212175&r1=212174&r2=212175&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/BuiltinsARM.def (original)
+++ cfe/trunk/include/clang/Basic/BuiltinsARM.def Wed Jul  2 07:56:02 2014
@@ -32,7 +32,9 @@ BUILTIN(__builtin_arm_ldrexd, "LLUiv*",
 BUILTIN(__builtin_arm_strexd, "iLLUiv*", "")
 
 BUILTIN(__builtin_arm_ldrex, "v.", "t")
+BUILTIN(__builtin_arm_ldaex, "v.", "t")
 BUILTIN(__builtin_arm_strex, "i.", "t")
+BUILTIN(__builtin_arm_stlex, "i.", "t")
 BUILTIN(__builtin_arm_clrex, "v", "")
 
 // VFP

Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=212175&r1=212174&r2=212175&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Wed Jul  2 07:56:02 2014
@@ -3074,9 +3074,12 @@ Value *CodeGenFunction::EmitARMBuiltinEx
   }
 
   if (BuiltinID == ARM::BI__builtin_arm_ldrexd ||
-      (BuiltinID == ARM::BI__builtin_arm_ldrex &&
+      ((BuiltinID == ARM::BI__builtin_arm_ldrex ||
+        BuiltinID == ARM::BI__builtin_arm_ldaex) &&
        getContext().getTypeSize(E->getType()) == 64)) {
-    Function *F = CGM.getIntrinsic(Intrinsic::arm_ldrexd);
+    Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_ldaex
+                                       ? Intrinsic::arm_ldaexd
+                                       : Intrinsic::arm_ldrexd);
 
     Value *LdPtr = EmitScalarExpr(E->getArg(0));
     Value *Val = Builder.CreateCall(F, Builder.CreateBitCast(LdPtr, Int8PtrTy),
@@ -3093,7 +3096,8 @@ Value *CodeGenFunction::EmitARMBuiltinEx
     return Builder.CreateBitCast(Val, ConvertType(E->getType()));
   }
 
-  if (BuiltinID == ARM::BI__builtin_arm_ldrex) {
+  if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
+      BuiltinID == ARM::BI__builtin_arm_ldaex) {
     Value *LoadAddr = EmitScalarExpr(E->getArg(0));
 
     QualType Ty = E->getType();
@@ -3102,7 +3106,10 @@ Value *CodeGenFunction::EmitARMBuiltinEx
                                                   getContext().getTypeSize(Ty));
     LoadAddr = Builder.CreateBitCast(LoadAddr, IntResTy->getPointerTo());
 
-    Function *F = CGM.getIntrinsic(Intrinsic::arm_ldrex, LoadAddr->getType());
+    Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_ldaex
+                                       ? Intrinsic::arm_ldaex
+                                       : Intrinsic::arm_ldrex,
+                                   LoadAddr->getType());
     Value *Val = Builder.CreateCall(F, LoadAddr, "ldrex");
 
     if (RealResTy->isPointerTy())
@@ -3114,9 +3121,12 @@ Value *CodeGenFunction::EmitARMBuiltinEx
   }
 
   if (BuiltinID == ARM::BI__builtin_arm_strexd ||
-      (BuiltinID == ARM::BI__builtin_arm_strex &&
+      ((BuiltinID == ARM::BI__builtin_arm_stlex ||
+        BuiltinID == ARM::BI__builtin_arm_strex) &&
        getContext().getTypeSize(E->getArg(0)->getType()) == 64)) {
-    Function *F = CGM.getIntrinsic(Intrinsic::arm_strexd);
+    Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex
+                                       ? Intrinsic::arm_stlexd
+                                       : Intrinsic::arm_strexd);
     llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty, NULL);
 
     Value *Tmp = CreateMemTemp(E->getArg(0)->getType());
@@ -3132,7 +3142,8 @@ Value *CodeGenFunction::EmitARMBuiltinEx
     return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "strexd");
   }
 
-  if (BuiltinID == ARM::BI__builtin_arm_strex) {
+  if (BuiltinID == ARM::BI__builtin_arm_strex ||
+      BuiltinID == ARM::BI__builtin_arm_stlex) {
     Value *StoreVal = EmitScalarExpr(E->getArg(0));
     Value *StoreAddr = EmitScalarExpr(E->getArg(1));
 
@@ -3148,7 +3159,10 @@ Value *CodeGenFunction::EmitARMBuiltinEx
       StoreVal = Builder.CreateZExtOrBitCast(StoreVal, Int32Ty);
     }
 
-    Function *F = CGM.getIntrinsic(Intrinsic::arm_strex, StoreAddr->getType());
+    Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex
+                                       ? Intrinsic::arm_stlex
+                                       : Intrinsic::arm_strex,
+                                   StoreAddr->getType());
     return Builder.CreateCall2(F, StoreVal, StoreAddr, "strex");
   }
 
@@ -3791,9 +3805,12 @@ Value *CodeGenFunction::EmitAArch64Built
     return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
   }
 
-  if (BuiltinID == AArch64::BI__builtin_arm_ldrex &&
+  if ((BuiltinID == AArch64::BI__builtin_arm_ldrex ||
+      BuiltinID == AArch64::BI__builtin_arm_ldaex) &&
       getContext().getTypeSize(E->getType()) == 128) {
-    Function *F = CGM.getIntrinsic(Intrinsic::aarch64_ldxp);
+    Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_ldaex
+                                       ? Intrinsic::aarch64_ldaxp
+                                       : Intrinsic::aarch64_ldxp);
 
     Value *LdPtr = EmitScalarExpr(E->getArg(0));
     Value *Val = Builder.CreateCall(F, Builder.CreateBitCast(LdPtr, Int8PtrTy),
@@ -3809,7 +3826,8 @@ Value *CodeGenFunction::EmitAArch64Built
     Val = Builder.CreateShl(Val0, ShiftCst, "shl", true /* nuw */);
     Val = Builder.CreateOr(Val, Val1);
     return Builder.CreateBitCast(Val, ConvertType(E->getType()));
-  } else if (BuiltinID == AArch64::BI__builtin_arm_ldrex) {
+  } else if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
+             BuiltinID == AArch64::BI__builtin_arm_ldaex) {
     Value *LoadAddr = EmitScalarExpr(E->getArg(0));
 
     QualType Ty = E->getType();
@@ -3818,7 +3836,10 @@ Value *CodeGenFunction::EmitAArch64Built
                                                   getContext().getTypeSize(Ty));
     LoadAddr = Builder.CreateBitCast(LoadAddr, IntResTy->getPointerTo());
 
-    Function *F = CGM.getIntrinsic(Intrinsic::aarch64_ldxr, LoadAddr->getType());
+    Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_ldaex
+                                       ? Intrinsic::aarch64_ldaxr
+                                       : Intrinsic::aarch64_ldxr,
+                                   LoadAddr->getType());
     Value *Val = Builder.CreateCall(F, LoadAddr, "ldxr");
 
     if (RealResTy->isPointerTy())
@@ -3828,9 +3849,12 @@ Value *CodeGenFunction::EmitAArch64Built
     return Builder.CreateBitCast(Val, RealResTy);
   }
 
-  if (BuiltinID == AArch64::BI__builtin_arm_strex &&
+  if ((BuiltinID == AArch64::BI__builtin_arm_strex ||
+       BuiltinID == AArch64::BI__builtin_arm_stlex) &&
       getContext().getTypeSize(E->getArg(0)->getType()) == 128) {
-    Function *F = CGM.getIntrinsic(Intrinsic::aarch64_stxp);
+    Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex
+                                       ? Intrinsic::aarch64_stlxp
+                                       : Intrinsic::aarch64_stxp);
     llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty, NULL);
 
     Value *One = llvm::ConstantInt::get(Int32Ty, 1);
@@ -3847,7 +3871,8 @@ Value *CodeGenFunction::EmitAArch64Built
     Value *StPtr = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)),
                                          Int8PtrTy);
     return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "stxp");
-  } else if (BuiltinID == AArch64::BI__builtin_arm_strex) {
+  } else if (BuiltinID == AArch64::BI__builtin_arm_strex ||
+             BuiltinID == AArch64::BI__builtin_arm_stlex) {
     Value *StoreVal = EmitScalarExpr(E->getArg(0));
     Value *StoreAddr = EmitScalarExpr(E->getArg(1));
 
@@ -3863,7 +3888,10 @@ Value *CodeGenFunction::EmitAArch64Built
       StoreVal = Builder.CreateZExtOrBitCast(StoreVal, Int64Ty);
     }
 
-    Function *F = CGM.getIntrinsic(Intrinsic::aarch64_stxr, StoreAddr->getType());
+    Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex
+                                       ? Intrinsic::aarch64_stlxr
+                                       : Intrinsic::aarch64_stxr,
+                                   StoreAddr->getType());
     return Builder.CreateCall2(F, StoreVal, StoreAddr, "stxr");
   }
 

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=212175&r1=212174&r2=212175&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Jul  2 07:56:02 2014
@@ -486,12 +486,18 @@ bool Sema::CheckNeonBuiltinFunctionCall(
 bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
                                         unsigned MaxWidth) {
   assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
+          BuiltinID == ARM::BI__builtin_arm_ldaex ||
           BuiltinID == ARM::BI__builtin_arm_strex ||
+          BuiltinID == ARM::BI__builtin_arm_stlex ||
           BuiltinID == AArch64::BI__builtin_arm_ldrex ||
-          BuiltinID == AArch64::BI__builtin_arm_strex) &&
+          BuiltinID == AArch64::BI__builtin_arm_ldaex ||
+          BuiltinID == AArch64::BI__builtin_arm_strex ||
+          BuiltinID == AArch64::BI__builtin_arm_stlex) &&
          "unexpected ARM builtin");
   bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex ||
-                 BuiltinID == AArch64::BI__builtin_arm_ldrex;
+                 BuiltinID == ARM::BI__builtin_arm_ldaex ||
+                 BuiltinID == AArch64::BI__builtin_arm_ldrex ||
+                 BuiltinID == AArch64::BI__builtin_arm_ldaex;
 
   DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
 
@@ -598,7 +604,9 @@ bool Sema::CheckARMBuiltinFunctionCall(u
   llvm::APSInt Result;
 
   if (BuiltinID == ARM::BI__builtin_arm_ldrex ||
-      BuiltinID == ARM::BI__builtin_arm_strex) {
+      BuiltinID == ARM::BI__builtin_arm_ldaex ||
+      BuiltinID == ARM::BI__builtin_arm_strex ||
+      BuiltinID == ARM::BI__builtin_arm_stlex) {
     return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64);
   }
 
@@ -627,7 +635,9 @@ bool Sema::CheckAArch64BuiltinFunctionCa
   llvm::APSInt Result;
 
   if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
-      BuiltinID == AArch64::BI__builtin_arm_strex) {
+      BuiltinID == AArch64::BI__builtin_arm_ldaex ||
+      BuiltinID == AArch64::BI__builtin_arm_strex ||
+      BuiltinID == AArch64::BI__builtin_arm_stlex) {
     return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128);
   }
 

Modified: cfe/trunk/test/CodeGen/builtins-arm-exclusive.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins-arm-exclusive.c?rev=212175&r1=212174&r2=212175&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/builtins-arm-exclusive.c (original)
+++ cfe/trunk/test/CodeGen/builtins-arm-exclusive.c Wed Jul  2 07:56:02 2014
@@ -1,5 +1,5 @@
 // REQUIRES: arm-registered-target
-// RUN: %clang_cc1 -Wall -Werror -triple thumbv7-linux-gnueabi -fno-signed-char -O3 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -Wall -Werror -triple thumbv8-linux-gnueabi -fno-signed-char -O3 -emit-llvm -o - %s | FileCheck %s
 // RUN: %clang_cc1 -Wall -Werror -triple arm64-apple-ios7.0 -O3 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-ARM64
 
 // Make sure the canonical use works before going into smaller details:
@@ -116,6 +116,90 @@ int test_ldrex(char *addr, long long *ad
   return sum;
 }
 
+int test_ldaex(char *addr, long long *addr64, float *addrfloat) {
+// CHECK-LABEL: @test_ldaex
+// CHECK-ARM64-LABEL: @test_ldaex
+  int sum = 0;
+  sum += __builtin_arm_ldaex(addr);
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldaex.p0i8(i8* %addr)
+// CHECK: and i32 [[INTRES]], 255
+
+// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldaxr.p0i8(i8* %addr)
+// CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
+// CHECK-ARM64: [[SEXTTMP:%.*]] = shl i32 [[TRUNCRES]], 24
+// CHECK-ARM64: ashr exact i32 [[SEXTTMP]], 24
+
+  sum += __builtin_arm_ldaex((short *)addr);
+// CHECK: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldaex.p0i16(i16* [[ADDR16]])
+// CHECK: [[TMPSEXT:%.*]] = shl i32 [[INTRES]], 16
+// CHECK: ashr exact i32 [[TMPSEXT]], 16
+
+// CHECK-ARM64: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
+// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldaxr.p0i16(i16* [[ADDR16]])
+// CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
+// CHECK-ARM64: [[TMPSEXT:%.*]] = shl i32 [[TRUNCRES]], 16
+// CHECK-ARM64: ashr exact i32 [[TMPSEXT]], 16
+
+  sum += __builtin_arm_ldaex((int *)addr);
+// CHECK: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
+// CHECK:  call i32 @llvm.arm.ldaex.p0i32(i32* [[ADDR32]])
+
+// CHECK-ARM64: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
+// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldaxr.p0i32(i32* [[ADDR32]])
+// CHECK-ARM64: trunc i64 [[INTRES]] to i32
+
+  sum += __builtin_arm_ldaex((long long *)addr);
+// CHECK: call { i32, i32 } @llvm.arm.ldaexd(i8* %addr)
+
+// CHECK-ARM64: [[ADDR64:%.*]] = bitcast i8* %addr to i64*
+// CHECK-ARM64: call i64 @llvm.aarch64.ldaxr.p0i64(i64* [[ADDR64]])
+
+  sum += __builtin_arm_ldaex(addr64);
+// CHECK: [[ADDR64_AS8:%.*]] = bitcast i64* %addr64 to i8*
+// CHECK: call { i32, i32 } @llvm.arm.ldaexd(i8* [[ADDR64_AS8]])
+
+// CHECK-ARM64: call i64 @llvm.aarch64.ldaxr.p0i64(i64* %addr64)
+
+  sum += __builtin_arm_ldaex(addrfloat);
+// CHECK: [[INTADDR:%.*]] = bitcast float* %addrfloat to i32*
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldaex.p0i32(i32* [[INTADDR]])
+// CHECK: bitcast i32 [[INTRES]] to float
+
+// CHECK-ARM64: [[INTADDR:%.*]] = bitcast float* %addrfloat to i32*
+// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldaxr.p0i32(i32* [[INTADDR]])
+// CHECK-ARM64: [[TRUNCRES:%.*]] = trunc i64 [[INTRES]] to i32
+// CHECK-ARM64: bitcast i32 [[TRUNCRES]] to float
+
+  sum += __builtin_arm_ldaex((double *)addr);
+// CHECK: [[STRUCTRES:%.*]] = tail call { i32, i32 } @llvm.arm.ldaexd(i8* %addr)
+// CHECK: [[RESHI:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 1
+// CHECK: [[RESLO:%.*]] = extractvalue { i32, i32 } [[STRUCTRES]], 0
+// CHECK: [[RESHI64:%.*]] = zext i32 [[RESHI]] to i64
+// CHECK: [[RESLO64:%.*]] = zext i32 [[RESLO]] to i64
+// CHECK: [[RESHIHI:%.*]] = shl nuw i64 [[RESHI64]], 32
+// CHECK: [[INTRES:%.*]] = or i64 [[RESHIHI]], [[RESLO64]]
+// CHECK: bitcast i64 [[INTRES]] to double
+
+// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldaxr.p0i64(i64* [[ADDR64]])
+// CHECK-ARM64: bitcast i64 [[INTRES]] to double
+
+  sum += *__builtin_arm_ldaex((int **)addr);
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldaex.p0i32(i32* [[ADDR32]])
+// CHECK: inttoptr i32 [[INTRES]] to i32*
+
+// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldaxr.p0i64(i64* [[ADDR64]])
+// CHECK-ARM64: inttoptr i64 [[INTRES]] to i32*
+
+  sum += __builtin_arm_ldaex((struct Simple **)addr)->a;
+// CHECK: [[INTRES:%.*]] = tail call i32 @llvm.arm.ldaex.p0i32(i32* [[ADDR32]])
+// CHECK: inttoptr i32 [[INTRES]] to %struct.Simple*
+
+// CHECK-ARM64: [[INTRES:%.*]] = tail call i64 @llvm.aarch64.ldaxr.p0i64(i64* [[ADDR64]])
+// CHECK-ARM64: inttoptr i64 [[INTRES]] to %struct.Simple*
+  return sum;
+}
+
 int test_strex(char *addr) {
 // CHECK-LABEL: @test_strex
 // CHECK-ARM64-LABEL: @test_strex
@@ -166,6 +250,56 @@ int test_strex(char *addr) {
   return res;
 }
 
+int test_stlex(char *addr) {
+// CHECK-LABEL: @test_stlex
+// CHECK-ARM64-LABEL: @test_stlex
+  int res = 0;
+  struct Simple var = {0};
+  res |= __builtin_arm_stlex(4, addr);
+// CHECK: call i32 @llvm.arm.stlex.p0i8(i32 4, i8* %addr)
+
+// CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i8(i64 4, i8* %addr)
+
+  res |= __builtin_arm_stlex(42, (short *)addr);
+// CHECK: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
+// CHECK:  call i32 @llvm.arm.stlex.p0i16(i32 42, i16* [[ADDR16]])
+
+// CHECK-ARM64: [[ADDR16:%.*]] = bitcast i8* %addr to i16*
+// CHECK-ARM64:  call i32 @llvm.aarch64.stlxr.p0i16(i64 42, i16* [[ADDR16]])
+
+  res |= __builtin_arm_stlex(42, (int *)addr);
+// CHECK: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
+// CHECK: call i32 @llvm.arm.stlex.p0i32(i32 42, i32* [[ADDR32]])
+
+// CHECK-ARM64: [[ADDR32:%.*]] = bitcast i8* %addr to i32*
+// CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i32(i64 42, i32* [[ADDR32]])
+
+  res |= __builtin_arm_stlex(42, (long long *)addr);
+// CHECK: call i32 @llvm.arm.stlexd(i32 42, i32 0, i8* %addr)
+
+// CHECK-ARM64: [[ADDR64:%.*]] = bitcast i8* %addr to i64*
+// CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i64(i64 42, i64* [[ADDR64]])
+
+  res |= __builtin_arm_stlex(2.71828f, (float *)addr);
+// CHECK: call i32 @llvm.arm.stlex.p0i32(i32 1076754509, i32* [[ADDR32]])
+
+// CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i32(i64 1076754509, i32* [[ADDR32]])
+
+  res |= __builtin_arm_stlex(3.14159, (double *)addr);
+// CHECK: call i32 @llvm.arm.stlexd(i32 -266631570, i32 1074340345, i8* %addr)
+
+// CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i64(i64 4614256650576692846, i64* [[ADDR64]])
+
+  res |= __builtin_arm_stlex(&var, (struct Simple **)addr);
+// CHECK: [[INTVAL:%.*]] = ptrtoint i16* %var to i32
+// CHECK: call i32 @llvm.arm.stlex.p0i32(i32 [[INTVAL]], i32* [[ADDR32]])
+
+// CHECK-ARM64: [[INTVAL:%.*]] = ptrtoint i16* %var to i64
+// CHECK-ARM64: call i32 @llvm.aarch64.stlxr.p0i64(i64 [[INTVAL]], i64* [[ADDR64]])
+
+  return res;
+}
+
 void test_clrex() {
 // CHECK-LABEL: @test_clrex
 // CHECK-ARM64-LABEL: @test_clrex
@@ -203,4 +337,31 @@ int test_strex_128(__int128 *addr, __int
 // CHECK-ARM64: [[ADDR8:%.*]] = bitcast i128* %addr to i8*
 // CHECK-ARM64: [[RES:%.*]] = tail call i32 @llvm.aarch64.stxp(i64 [[VALLO]], i64 [[VALHI]], i8* [[ADDR8]])
 }
+
+__int128 test_ldaex_128(__int128 *addr) {
+// CHECK-ARM64-LABEL: @test_ldaex_128
+
+  return __builtin_arm_ldaex(addr);
+// CHECK-ARM64: [[ADDR8:%.*]] = bitcast i128* %addr to i8*
+// CHECK-ARM64: [[STRUCTRES:%.*]] = tail call { i64, i64 } @llvm.aarch64.ldaxp(i8* [[ADDR8]])
+// CHECK-ARM64: [[RESHI:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 1
+// CHECK-ARM64: [[RESLO:%.*]] = extractvalue { i64, i64 } [[STRUCTRES]], 0
+// CHECK-ARM64: [[RESHI64:%.*]] = zext i64 [[RESHI]] to i128
+// CHECK-ARM64: [[RESLO64:%.*]] = zext i64 [[RESLO]] to i128
+// CHECK-ARM64: [[RESHIHI:%.*]] = shl nuw i128 [[RESHI64]], 64
+// CHECK-ARM64: [[INTRES:%.*]] = or i128 [[RESHIHI]], [[RESLO64]]
+// CHECK-ARM64: ret i128 [[INTRES]]
+}
+
+int test_stlex_128(__int128 *addr, __int128 val) {
+// CHECK-ARM64-LABEL: @test_stlex_128
+
+  return __builtin_arm_stlex(val, addr);
+// CHECK-ARM64: [[VALLO:%.*]] = trunc i128 %val to i64
+// CHECK-ARM64: [[VALHI128:%.*]] = lshr i128 %val, 64
+// CHECK-ARM64: [[VALHI:%.*]] = trunc i128 [[VALHI128]] to i64
+// CHECK-ARM64: [[ADDR8:%.*]] = bitcast i128* %addr to i8*
+// CHECK-ARM64: [[RES:%.*]] = tail call i32 @llvm.aarch64.stlxp(i64 [[VALLO]], i64 [[VALHI]], i8* [[ADDR8]])
+}
+
 #endif

Modified: cfe/trunk/test/Sema/builtins-arm-exclusive.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/builtins-arm-exclusive.c?rev=212175&r1=212174&r2=212175&view=diff
==============================================================================
--- cfe/trunk/test/Sema/builtins-arm-exclusive.c (original)
+++ cfe/trunk/test/Sema/builtins-arm-exclusive.c Wed Jul  2 07:56:02 2014
@@ -55,6 +55,57 @@ int test_strex(char *addr) {
   return res;
 }
 
+int test_ldaex(char *addr) {
+  int sum = 0;
+  sum += __builtin_arm_ldaex(addr);
+  sum += __builtin_arm_ldaex((short *)addr);
+  sum += __builtin_arm_ldaex((int *)addr);
+  sum += __builtin_arm_ldaex((long long *)addr);
+  sum += __builtin_arm_ldaex((float *)addr);
+  sum += __builtin_arm_ldaex((double *)addr);
+  sum += *__builtin_arm_ldaex((int **)addr);
+  sum += __builtin_arm_ldaex((struct Simple **)addr)->a;
+  sum += __builtin_arm_ldaex((volatile char *)addr);
+  sum += __builtin_arm_ldaex((const volatile char *)addr);
+
+  // In principle this might be valid, but stick to ints and floats for scalar
+  // types at the moment.
+  sum += __builtin_arm_ldaex((struct Simple *)addr).a; // expected-error {{address argument to atomic builtin must be a pointer to}}
+
+  sum += __builtin_arm_ldaex((__int128 *)addr); // expected-error {{__int128 is not supported on this target}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 1,2,4 or 8 byte type}}
+
+  __builtin_arm_ldaex(); // expected-error {{too few arguments to function call}}
+  __builtin_arm_ldaex(1, 2); // expected-error {{too many arguments to function call}}
+  return sum;
+}
+
+int test_stlex(char *addr) {
+  int res = 0;
+  struct Simple var = {0};
+  res |= __builtin_arm_stlex(4, addr);
+  res |= __builtin_arm_stlex(42, (short *)addr);
+  res |= __builtin_arm_stlex(42, (int *)addr);
+  res |= __builtin_arm_stlex(42, (long long *)addr);
+  res |= __builtin_arm_stlex(2.71828f, (float *)addr);
+  res |= __builtin_arm_stlex(3.14159, (double *)addr);
+  res |= __builtin_arm_stlex(&var, (struct Simple **)addr);
+
+  res |= __builtin_arm_stlex(42, (volatile char *)addr);
+  res |= __builtin_arm_stlex(42, (char *const)addr);
+  res |= __builtin_arm_stlex(42, (const char *)addr); // expected-warning {{passing 'const char *' to parameter of type 'volatile char *' discards qualifiers}}
+
+
+  res |= __builtin_arm_stlex(var, (struct Simple *)addr); // expected-error {{address argument to atomic builtin must be a pointer to}}
+  res |= __builtin_arm_stlex(var, (struct Simple **)addr); // expected-error {{passing 'struct Simple' to parameter of incompatible type 'struct Simple *'}}
+  res |= __builtin_arm_stlex(&var, (struct Simple **)addr).a; // expected-error {{is not a structure or union}}
+
+  res |= __builtin_arm_stlex(1, (__int128 *)addr); // expected-error {{__int128 is not supported on this target}} expected-error {{address argument to load or store exclusive builtin must be a pointer to 1,2,4 or 8 byte type}}
+
+  __builtin_arm_stlex(1); // expected-error {{too few arguments to function call}}
+  __builtin_arm_stlex(1, 2, 3); // expected-error {{too many arguments to function call}}
+  return res;
+}
+
 void test_clrex() {
   __builtin_arm_clrex();
   __builtin_arm_clrex(1); // expected-error {{too many arguments to function call}}

Modified: cfe/trunk/test/Sema/builtins-arm64-exclusive.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/builtins-arm64-exclusive.c?rev=212175&r1=212174&r2=212175&view=diff
==============================================================================
--- cfe/trunk/test/Sema/builtins-arm64-exclusive.c (original)
+++ cfe/trunk/test/Sema/builtins-arm64-exclusive.c Wed Jul  2 07:56:02 2014
@@ -53,6 +53,55 @@ int test_strex(char *addr) {
   return res;
 }
 
+int test_ldaex(char *addr) {
+  int sum = 0;
+  sum += __builtin_arm_ldaex(addr);
+  sum += __builtin_arm_ldaex((short *)addr);
+  sum += __builtin_arm_ldaex((int *)addr);
+  sum += __builtin_arm_ldaex((long long *)addr);
+  sum += __builtin_arm_ldaex((__int128 *)addr);
+  sum += __builtin_arm_ldaex((float *)addr);
+  sum += __builtin_arm_ldaex((double *)addr);
+  sum += *__builtin_arm_ldaex((int **)addr);
+  sum += __builtin_arm_ldaex((struct Simple **)addr)->a;
+  sum += __builtin_arm_ldaex((volatile char *)addr);
+  sum += __builtin_arm_ldaex((const volatile char *)addr);
+
+  // In principle this might be valid, but stick to ints and floats for scalar
+  // types at the moment.
+  sum += __builtin_arm_ldaex((struct Simple *)addr).a; // expected-error {{address argument to atomic builtin must be a pointer to}}
+
+  __builtin_arm_ldaex(); // expected-error {{too few arguments to function call}}
+  __builtin_arm_ldaex(1, 2); // expected-error {{too many arguments to function call}}
+  return sum;
+}
+
+int test_stlex(char *addr) {
+  int res = 0;
+  struct Simple var = {0};
+  res |= __builtin_arm_stlex(4, addr);
+  res |= __builtin_arm_stlex(42, (short *)addr);
+  res |= __builtin_arm_stlex(42, (int *)addr);
+  res |= __builtin_arm_stlex(42, (long long *)addr);
+  res |= __builtin_arm_stlex(42, (__int128 *)addr);
+  res |= __builtin_arm_stlex(2.71828f, (float *)addr);
+  res |= __builtin_arm_stlex(3.14159, (double *)addr);
+  res |= __builtin_arm_stlex(&var, (struct Simple **)addr);
+
+  res |= __builtin_arm_stlex(42, (volatile char *)addr);
+  res |= __builtin_arm_stlex(42, (char *const)addr);
+  res |= __builtin_arm_stlex(42, (const char *)addr); // expected-warning {{passing 'const char *' to parameter of type 'volatile char *' discards qualifiers}}
+
+
+  res |= __builtin_arm_stlex(var, (struct Simple *)addr); // expected-error {{address argument to atomic builtin must be a pointer to}}
+  res |= __builtin_arm_stlex(var, (struct Simple **)addr); // expected-error {{passing 'struct Simple' to parameter of incompatible type 'struct Simple *'}}
+  res |= __builtin_arm_stlex(&var, (struct Simple **)addr).a; // expected-error {{is not a structure or union}}
+
+  __builtin_arm_stlex(1); // expected-error {{too few arguments to function call}}
+  __builtin_arm_stlex(1, 2, 3); // expected-error {{too many arguments to function call}}
+  return res;
+}
+
 void test_clrex() {
   __builtin_arm_clrex();
   __builtin_arm_clrex(1); // expected-error {{too many arguments to function call}}





More information about the cfe-commits mailing list