[llvm] r276183 - [AArch64][FastISel] Select -O0 legal cmpxchg.

Ahmed Bougacha via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 20 14:12:32 PDT 2016


Author: ab
Date: Wed Jul 20 16:12:32 2016
New Revision: 276183

URL: http://llvm.org/viewvc/llvm-project?rev=276183&view=rev
Log:
[AArch64][FastISel] Select -O0 legal cmpxchg.

At -O0, cmpxchg survives AtomicExpand: it's mostly straightforward
to select it in fast-isel, and let the pseudo be expanded later.

extractvalues on the result are the tricky part: the generic logic
only works for legal types (and it would be painful to make it
support illegal types), so we can only support i32/i64 cmpxchg.

Added:
    llvm/trunk/test/CodeGen/AArch64/fast-isel-cmpxchg.ll
Modified:
    llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp
    llvm/trunk/test/CodeGen/AArch64/cmpxchg-O0.ll

Modified: llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp?rev=276183&r1=276182&r2=276183&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64FastISel.cpp Wed Jul 20 16:12:32 2016
@@ -134,6 +134,7 @@ private:
   bool selectFRem(const Instruction *I);
   bool selectSDiv(const Instruction *I);
   bool selectGetElementPtr(const Instruction *I);
+  bool selectAtomicCmpXchg(const AtomicCmpXchgInst *I);
 
   // Utility helper routines.
   bool isTypeLegal(Type *Ty, MVT &VT);
@@ -4940,6 +4941,58 @@ bool AArch64FastISel::selectGetElementPt
   return true;
 }
 
+bool AArch64FastISel::selectAtomicCmpXchg(const AtomicCmpXchgInst *I) {
+  assert(TM.getOptLevel() == CodeGenOpt::None &&
+         "cmpxchg survived AtomicExpand at optlevel > -O0");
+
+  auto *RetPairTy = cast<StructType>(I->getType());
+  Type *RetTy = RetPairTy->getTypeAtIndex(0U);
+  assert(RetPairTy->getTypeAtIndex(1U)->isIntegerTy(1) &&
+         "cmpxchg has a non-i1 status result");
+
+  MVT VT;
+  if (!isTypeLegal(RetTy, VT))
+    return false;
+
+  const TargetRegisterClass *ResRC;
+  unsigned Opc;
+  // This only supports i32/i64, because i8/i16 aren't legal, and the generic
+  // extractvalue selection doesn't support that.
+  if (VT == MVT::i32) {
+    Opc = AArch64::CMP_SWAP_32;
+    ResRC = &AArch64::GPR32RegClass;
+  } else if (VT == MVT::i64) {
+    Opc = AArch64::CMP_SWAP_64;
+    ResRC = &AArch64::GPR64RegClass;
+  } else {
+    return false;
+  }
+
+  const MCInstrDesc &II = TII.get(Opc);
+
+  const unsigned AddrReg = constrainOperandRegClass(
+      II, getRegForValue(I->getPointerOperand()), II.getNumDefs());
+  const unsigned DesiredReg = constrainOperandRegClass(
+      II, getRegForValue(I->getCompareOperand()), II.getNumDefs() + 1);
+  const unsigned NewReg = constrainOperandRegClass(
+      II, getRegForValue(I->getNewValOperand()), II.getNumDefs() + 2);
+
+  const unsigned ResultReg1 = createResultReg(ResRC);
+  const unsigned ResultReg2 = createResultReg(&AArch64::GPR32RegClass);
+
+  // FIXME: MachineMemOperand doesn't support cmpxchg yet.
+  BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
+      .addReg(ResultReg1, RegState::Define)
+      .addReg(ResultReg2, RegState::Define)
+      .addReg(AddrReg)
+      .addReg(DesiredReg)
+      .addReg(NewReg);
+
+  assert((ResultReg1 + 1) == ResultReg2 && "Nonconsecutive result registers.");
+  updateValueMap(I, ResultReg1, 2);
+  return true;
+}
+
 bool AArch64FastISel::fastSelectInstruction(const Instruction *I) {
   switch (I->getOpcode()) {
   default:
@@ -5013,6 +5066,8 @@ bool AArch64FastISel::fastSelectInstruct
     return selectFRem(I);
   case Instruction::GetElementPtr:
     return selectGetElementPtr(I);
+  case Instruction::AtomicCmpXchg:
+    return selectAtomicCmpXchg(cast<AtomicCmpXchgInst>(I));
   }
 
   // fall-back to target-independent instruction selection.

Modified: llvm/trunk/test/CodeGen/AArch64/cmpxchg-O0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/cmpxchg-O0.ll?rev=276183&r1=276182&r2=276183&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/cmpxchg-O0.ll (original)
+++ llvm/trunk/test/CodeGen/AArch64/cmpxchg-O0.ll Wed Jul 20 16:12:32 2016
@@ -1,4 +1,4 @@
-; RUN: llc -verify-machineinstrs -mtriple=aarch64-linux-gnu -O0 %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -mtriple=aarch64-linux-gnu -O0 -fast-isel=0 %s -o - | FileCheck %s
 
 define { i8, i1 } @test_cmpxchg_8(i8* %addr, i8 %desired, i8 %new) nounwind {
 ; CHECK-LABEL: test_cmpxchg_8:

Added: llvm/trunk/test/CodeGen/AArch64/fast-isel-cmpxchg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/fast-isel-cmpxchg.ll?rev=276183&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/fast-isel-cmpxchg.ll (added)
+++ llvm/trunk/test/CodeGen/AArch64/fast-isel-cmpxchg.ll Wed Jul 20 16:12:32 2016
@@ -0,0 +1,72 @@
+; RUN: llc -mtriple=aarch64-- -O0 -fast-isel -fast-isel-abort=4 -verify-machineinstrs < %s | FileCheck %s
+
+; CHECK-LABEL: cmpxchg_monotonic_32:
+; CHECK: [[RETRY:.LBB[0-9_]+]]:
+; CHECK-NEXT:     ldaxr [[OLD:w[0-9]+]], [x0]
+; CHECK-NEXT:     cmp [[OLD]], w1
+; CHECK-NEXT:     b.ne [[DONE:.LBB[0-9_]+]]
+; CHECK-NEXT: // BB#2:
+; CHECK-NEXT:     stlxr [[STATUS:w[0-9]+]], w2, [x0]
+; CHECK-NEXT:     cbnz [[STATUS]], [[RETRY]]
+; CHECK-NEXT: [[DONE]]:
+; CHECK-NEXT:     and [[STATUS32:w[0-9]+]], [[STATUS]], #0x1
+; CHECK-NEXT:     str [[STATUS32]], [x3]
+; CHECK-NEXT:     mov w0, [[OLD]]
+; CHECK-NEXT:     ret
+define i32 @cmpxchg_monotonic_32(i32* %p, i32 %cmp, i32 %new, i32* %ps) #0 {
+  %tmp0 = cmpxchg i32* %p, i32 %cmp, i32 %new monotonic monotonic
+  %tmp1 = extractvalue { i32, i1 } %tmp0, 0
+  %tmp2 = extractvalue { i32, i1 } %tmp0, 1
+  %tmp3 = zext i1 %tmp2 to i32
+  store i32 %tmp3, i32* %ps
+  ret i32 %tmp1
+}
+
+; CHECK-LABEL: cmpxchg_acq_rel_32_load:
+; CHECK:      // BB#0:
+; CHECK-NEXT:     ldr [[NEW:w[0-9]+]], [x2]
+; CHECK-NEXT: [[RETRY:.LBB[0-9_]+]]:
+; CHECK-NEXT:     ldaxr [[OLD:w[0-9]+]], [x0]
+; CHECK-NEXT:     cmp [[OLD]], w1
+; CHECK-NEXT:     b.ne [[DONE:.LBB[0-9_]+]]
+; CHECK-NEXT: // BB#2:
+; CHECK-NEXT:     stlxr [[STATUS:w[0-9]+]], [[NEW]], [x0]
+; CHECK-NEXT:     cbnz [[STATUS]], [[RETRY]]
+; CHECK-NEXT: [[DONE]]:
+; CHECK-NEXT:     and [[STATUS32:w[0-9]+]], [[STATUS]], #0x1
+; CHECK-NEXT:     str [[STATUS32]], [x3]
+; CHECK-NEXT:     mov w0, [[OLD]]
+; CHECK-NEXT:     ret
+define i32 @cmpxchg_acq_rel_32_load(i32* %p, i32 %cmp, i32* %pnew, i32* %ps) #0 {
+  %new = load i32, i32* %pnew
+  %tmp0 = cmpxchg i32* %p, i32 %cmp, i32 %new acq_rel acquire
+  %tmp1 = extractvalue { i32, i1 } %tmp0, 0
+  %tmp2 = extractvalue { i32, i1 } %tmp0, 1
+  %tmp3 = zext i1 %tmp2 to i32
+  store i32 %tmp3, i32* %ps
+  ret i32 %tmp1
+}
+
+; CHECK-LABEL: cmpxchg_seq_cst_64:
+; CHECK: [[RETRY:.LBB[0-9_]+]]:
+; CHECK-NEXT:     ldaxr [[OLD:x[0-9]+]], [x0]
+; CHECK-NEXT:     cmp [[OLD]], x1
+; CHECK-NEXT:     b.ne [[DONE:.LBB[0-9_]+]]
+; CHECK-NEXT: // BB#2:
+; CHECK-NEXT:     stlxr [[STATUS:w[0-9]+]], x2, [x0]
+; CHECK-NEXT:     cbnz [[STATUS]], [[RETRY]]
+; CHECK-NEXT: [[DONE]]:
+; CHECK-NEXT:     and [[STATUS32:w[0-9]+]], [[STATUS]], #0x1
+; CHECK-NEXT:     str [[STATUS32]], [x3]
+; CHECK-NEXT:     mov x0, [[OLD]]
+; CHECK-NEXT:     ret
+define i64 @cmpxchg_seq_cst_64(i64* %p, i64 %cmp, i64 %new, i32* %ps) #0 {
+  %tmp0 = cmpxchg i64* %p, i64 %cmp, i64 %new seq_cst seq_cst
+  %tmp1 = extractvalue { i64, i1 } %tmp0, 0
+  %tmp2 = extractvalue { i64, i1 } %tmp0, 1
+  %tmp3 = zext i1 %tmp2 to i32
+  store i32 %tmp3, i32* %ps
+  ret i64 %tmp1
+}
+
+attributes #0 = { nounwind }




More information about the llvm-commits mailing list