[PowerPC] Fix L[D|W]ARX Implementation
authorAlbion Fung <albionapc@gmail.com>
Tue, 13 Jul 2021 16:01:53 +0000 (11:01 -0500)
committerAlbion Fung <albionapc@gmail.com>
Tue, 13 Jul 2021 16:02:07 +0000 (11:02 -0500)
LDARX and LWARX sometimes gets optimized out by the compiler
when it is critical to the correctness of the code. This inline asm generation
ensures that it preserved.

Differential Revision: https://reviews.llvm.org/D105754

clang/lib/CodeGen/CGBuiltin.cpp
clang/test/CodeGen/builtins-ppc-xlcompat-LoadReseve-StoreCond-64bit-only.c
clang/test/CodeGen/builtins-ppc-xlcompat-LoadReseve-StoreCond.c
llvm/include/llvm/IR/IntrinsicsPowerPC.td
llvm/lib/Target/PowerPC/PPCInstr64Bit.td
llvm/lib/Target/PowerPC/PPCInstrInfo.td
llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-LoadReserve-StoreCond-64bit-only.ll
llvm/test/CodeGen/PowerPC/builtins-ppc-xlcompat-LoadReserve-StoreCond.ll

index 355ed8f..baa1436 100644 (file)
@@ -994,6 +994,46 @@ static llvm::Value *EmitBitTestIntrinsic(CodeGenFunction &CGF,
       ShiftedByte, llvm::ConstantInt::get(CGF.Int8Ty, 1), "bittest.res");
 }
 
+static llvm::Value *emitPPCLoadReserveIntrinsic(CodeGenFunction &CGF,
+                                                unsigned BuiltinID,
+                                                const CallExpr *E) {
+  Value *Addr = CGF.EmitScalarExpr(E->getArg(0));
+
+  SmallString<64> Asm;
+  raw_svector_ostream AsmOS(Asm);
+  llvm::IntegerType *RetType = CGF.Int32Ty;
+
+  switch (BuiltinID) {
+  case clang::PPC::BI__builtin_ppc_ldarx:
+    AsmOS << "ldarx ";
+    RetType = CGF.Int64Ty;
+    break;
+  case clang::PPC::BI__builtin_ppc_lwarx:
+    AsmOS << "lwarx ";
+    RetType = CGF.Int32Ty;
+    break;
+  default:
+    llvm_unreachable("Expected only PowerPC load reserve intrinsics");
+  }
+
+  AsmOS << "$0, ${1:y}";
+
+  std::string Constraints = "=r,*Z,~{memory}";
+  std::string MachineClobbers = CGF.getTarget().getClobbers();
+  if (!MachineClobbers.empty()) {
+    Constraints += ',';
+    Constraints += MachineClobbers;
+  }
+
+  llvm::Type *IntPtrType = RetType->getPointerTo();
+  llvm::FunctionType *FTy =
+      llvm::FunctionType::get(RetType, {IntPtrType}, false);
+
+  llvm::InlineAsm *IA =
+      llvm::InlineAsm::get(FTy, Asm, Constraints, /*hasSideEffects=*/true);
+  return CGF.Builder.CreateCall(IA, {Addr});
+}
+
 namespace {
 enum class MSVCSetJmpKind {
   _setjmpex,
@@ -15532,6 +15572,9 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
     return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xchg, E,
                                  llvm::AtomicOrdering::Monotonic);
   }
+  case PPC::BI__builtin_ppc_ldarx:
+  case PPC::BI__builtin_ppc_lwarx:
+    return emitPPCLoadReserveIntrinsic(*this, BuiltinID, E);
   }
 }
 
index 80bb4de..f0a8ff1 100644 (file)
@@ -1,27 +1,23 @@
 // RUN: not %clang_cc1 -triple=powerpc-unknown-aix -emit-llvm %s -o - 2>&1 |\
 // RUN: FileCheck %s --check-prefix=CHECK32-ERROR
-// RUN: %clang_cc1 -triple=powerpc64-unknown-aix -emit-llvm %s -o - | \
+// RUN: %clang_cc1 -O2 -triple=powerpc64-unknown-aix -emit-llvm %s -o - | \
 // RUN: FileCheck %s --check-prefix=CHECK64
-// RUN: %clang_cc1 -triple=powerpc64le-unknown-unknown -emit-llvm %s \
+// RUN: %clang_cc1 -O2 -triple=powerpc64le-unknown-unknown -emit-llvm %s \
 // RUN:  -o - | FileCheck %s --check-prefix=CHECK64
-// RUN: %clang_cc1 -triple=powerpc64-unknown-unknown -emit-llvm %s \
+// RUN: %clang_cc1 -O2 -triple=powerpc64-unknown-unknown -emit-llvm %s \
 // RUN:  -o - | FileCheck %s --check-prefix=CHECK64
 
 long test_ldarx(volatile long* a) {
   // CHECK64-LABEL: @test_ldarx
-  // CHECK64: %0 = load i64*, i64** %a.addr, align 8
-  // CHECK64: %1 = bitcast i64* %0 to i8*
-  // CHECK64: %2 = call i64 @llvm.ppc.ldarx(i8* %1)
+  // CHECK64: %0 = tail call i64 asm sideeffect "ldarx $0, ${1:y}", "=r,*Z,~{memory}"(i64* %a)
   // CHECK32-ERROR: error: this builtin is only available on 64-bit targets
   return __ldarx(a);
 }
 
 int test_stdcx(volatile long* addr, long val) {
   // CHECK64-LABEL: @test_stdcx
-  // CHECK64: %0 = load i64*, i64** %addr.addr, align 8
-  // CHECK64: %1 = bitcast i64* %0 to i8*
-  // CHECK64: %2 = load i64, i64* %val.addr, align 8
-  // CHECK64: %3 = call i32 @llvm.ppc.stdcx(i8* %1, i64 %2)
+  // CHECK64: %0 = bitcast i64* %addr to i8*
+  // CHECK64: %1 = tail call i32 @llvm.ppc.stdcx(i8* %0, i64 %val)
   // CHECK32-ERROR: error: this builtin is only available on 64-bit targets
   return __stdcx(addr, val);
 }
index 5b80797..4ffa29a 100644 (file)
@@ -1,22 +1,20 @@
-// RUN: %clang_cc1 -triple=powerpc-unknown-aix -emit-llvm %s -o - | \
+// RUN: %clang_cc1 -O2 -triple=powerpc-unknown-aix -emit-llvm %s -o - | \
 // RUN: FileCheck %s
-// RUN: %clang_cc1 -triple=powerpc64-unknown-aix -emit-llvm %s -o - | \
+// RUN: %clang_cc1 -O2 -triple=powerpc64-unknown-aix -emit-llvm %s -o - | \
 // RUN: FileCheck %s
-// RUN: %clang_cc1 -triple=powerpc64le-unknown-unknown -emit-llvm %s \
+// RUN: %clang_cc1 -O2 -triple=powerpc64le-unknown-unknown -emit-llvm %s \
 // RUN:  -o - | FileCheck %s
-// RUN: %clang_cc1 -triple=powerpc64-unknown-unknown -emit-llvm %s \
+// RUN: %clang_cc1 -O2 -triple=powerpc64-unknown-unknown -emit-llvm %s \
 // RUN:  -o - | FileCheck %s
 
 int test_lwarx(volatile int* a) {
   // CHECK: @test_lwarx
-  // CHECK: %1 = bitcast i32* %0 to i8*
-  // CHECK: %2 = call i32 @llvm.ppc.lwarx(i8* %1)
+  // CHECK: %0 = tail call i32 asm sideeffect "lwarx $0, ${1:y}", "=r,*Z,~{memory}"(i32* %a)
   return __lwarx(a);
 }
 int test_stwcx(volatile int* a, int val) {
   // CHECK: @test_stwcx
-  // CHECK: %1 = bitcast i32* %0 to i8*
-  // CHECK: %2 = load i32, i32* %val.addr, align 4
-  // CHECK: %3 = call i32 @llvm.ppc.stwcx(i8* %1, i32 %2)
+  // CHECK: %0 = bitcast i32* %a to i8*
+  // CHECK: %1 = tail call i32 @llvm.ppc.stwcx(i8* %0, i32 %val)
   return __stwcx(a, val);
 }
index c02d964..452d3a0 100644 (file)
@@ -1565,9 +1565,5 @@ let TargetPrefix = "ppc" in {
   def int_ppc_stwcx : GCCBuiltin<"__builtin_ppc_stwcx">,
                       Intrinsic<[llvm_i32_ty], [llvm_ptr_ty, llvm_i32_ty],
                                 [IntrWriteMem]>;
-  def int_ppc_lwarx : GCCBuiltin<"__builtin_ppc_lwarx">,
-                      Intrinsic<[llvm_i32_ty], [llvm_ptr_ty], [IntrNoMem]>;
-  def int_ppc_ldarx : GCCBuiltin<"__builtin_ppc_ldarx">,
-                      Intrinsic<[llvm_i64_ty], [llvm_ptr_ty], [IntrNoMem]>;
 }
 
index aad6c5d..6dd1a67 100644 (file)
@@ -1723,8 +1723,6 @@ def SLBSYNC : XForm_0<31, 338, (outs), (ins), "slbsync", IIC_SprSLBSYNC, []>;
 
 def : Pat<(int_ppc_stdcx ForceXForm:$dst, g8rc:$A),
           (STDCX g8rc:$A, ForceXForm:$dst)>;
-def : Pat<(int_ppc_ldarx ForceXForm:$dst),
-          (LDARX ForceXForm:$dst)>;
 def : Pat<(int_ppc_tdw g8rc:$A, g8rc:$B, i32:$IMM),
           (TD $IMM, $A, $B)>;
 
index 4ee32d3..0ca4ef6 100644 (file)
@@ -5413,8 +5413,6 @@ def DWBytes3210 {
 def : Pat<(i64 (bitreverse i64:$A)),
   (OR8 (RLDICR DWBytes7654.DWord, 32, 31), DWBytes3210.DWord)>;
 
-def : Pat<(int_ppc_lwarx ForceXForm:$dst),
-          (LWARX ForceXForm:$dst)>;
 def : Pat<(int_ppc_stwcx ForceXForm:$dst, gprc:$A),
           (STWCX gprc:$A, ForceXForm:$dst)>;
 def : Pat<(int_ppc_tw gprc:$A, gprc:$B, i32:$IMM),
index d845a1c..d00901f 100644 (file)
@@ -10,17 +10,18 @@ declare i64 @llvm.ppc.ldarx(i8*)
 define dso_local i64 @test_ldarx(i64* readnone %a) {
 ; CHECK-LABEL: test_ldarx:
 ; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
 ; CHECK-NEXT:    ldarx 3, 0, 3
+; CHECK-NEXT:    #NO_APP
 ; CHECK-NEXT:    blr
 entry:
-  %0 = bitcast i64* %a to i8*
-  %1 = tail call i64 @llvm.ppc.ldarx(i8* %0)
-  ret i64 %1
+  %0 = call i64 asm sideeffect "ldarx $0, ${1:y}", "=r,*Z,~{memory}"(i64* %a)
+  ret i64 %0
 }
 
 declare i32 @llvm.ppc.stdcx(i8*, i64)
-define dso_local i64 @test(i64* %a, i64 %b) {
-; CHECK-LABEL: test:
+define dso_local i64 @test_stdcx(i64* %a, i64 %b) {
+; CHECK-LABEL: test_stdcx:
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    stdcx. 4, 0, 3
 ; CHECK-NEXT:    mfocrf 3, 128
index 462b57f..7b16510 100644 (file)
@@ -12,18 +12,21 @@ declare i32 @llvm.ppc.lwarx(i8*)
 define dso_local signext i32 @test_lwarx(i32* readnone %a) {
 ; CHECK-64-LABEL: test_lwarx:
 ; CHECK-64:       # %bb.0: # %entry
+; CHECK-64-NEXT:    #APP
 ; CHECK-64-NEXT:    lwarx 3, 0, 3
+; CHECK-64-NEXT:    #NO_APP
 ; CHECK-64-NEXT:    extsw 3, 3
 ; CHECK-64-NEXT:    blr
 ;
 ; CHECK-32-LABEL: test_lwarx:
 ; CHECK-32:       # %bb.0: # %entry
+; CHECK-32-NEXT:    #APP
 ; CHECK-32-NEXT:    lwarx 3, 0, 3
+; CHECK-32-NEXT:    #NO_APP
 ; CHECK-32-NEXT:    blr
 entry:
-  %0 = bitcast i32* %a to i8*
-  %1 = tail call i32 @llvm.ppc.lwarx(i8* %0)
-  ret i32 %1
+  %0 = call i32 asm sideeffect "lwarx $0, ${1:y}", "=r,*Z,~{memory}"(i32* %a)
+  ret i32 %0
 }
 
 declare i32 @llvm.ppc.stwcx(i8*, i32)