]> granicus.if.org Git - llvm/commitdiff
ARM: fix big-endian 64-bit cmpxchg.
authorTim Northover <tnorthover@apple.com>
Fri, 30 Jun 2017 19:51:02 +0000 (19:51 +0000)
committerTim Northover <tnorthover@apple.com>
Fri, 30 Jun 2017 19:51:02 +0000 (19:51 +0000)
On big-endian machines the high and low parts of the value accessed by ldrexd
and strexd are swapped around. To account for this we swap inputs and outputs
in ISelLowering.

Patch by Bharathi Seshadri.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306865 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMISelLowering.cpp
test/CodeGen/ARM/cmpxchg-O0-be.ll [new file with mode: 0644]

index 2bcc707e9fc3c00a0efe37ca902fc4e823fe9fcf..e42514acd76f0c60a4fb957537a0f383c0888b06 100644 (file)
@@ -7580,6 +7580,9 @@ static SDValue createGPRPairNode(SelectionDAG &DAG, SDValue V) {
   SDValue VHi = DAG.getAnyExtOrTrunc(
       DAG.getNode(ISD::SRL, dl, MVT::i64, V, DAG.getConstant(32, dl, MVT::i32)),
       dl, MVT::i32);
+  bool isBigEndian = DAG.getDataLayout().isBigEndian();
+  if (isBigEndian)
+    std::swap (VLo, VHi);
   SDValue RegClass =
       DAG.getTargetConstant(ARM::GPRPairRegClassID, dl, MVT::i32);
   SDValue SubReg0 = DAG.getTargetConstant(ARM::gsub_0, dl, MVT::i32);
@@ -7607,10 +7610,14 @@ static void ReplaceCMP_SWAP_64Results(SDNode *N,
   MemOp[0] = cast<MemSDNode>(N)->getMemOperand();
   cast<MachineSDNode>(CmpSwap)->setMemRefs(MemOp, MemOp + 1);
 
-  Results.push_back(DAG.getTargetExtractSubreg(ARM::gsub_0, SDLoc(N), MVT::i32,
-                                               SDValue(CmpSwap, 0)));
-  Results.push_back(DAG.getTargetExtractSubreg(ARM::gsub_1, SDLoc(N), MVT::i32,
-                                               SDValue(CmpSwap, 0)));
+  bool isBigEndian = DAG.getDataLayout().isBigEndian();
+
+  Results.push_back(
+      DAG.getTargetExtractSubreg(isBigEndian ? ARM::gsub_1 : ARM::gsub_0,
+                                 SDLoc(N), MVT::i32, SDValue(CmpSwap, 0)));
+  Results.push_back(
+      DAG.getTargetExtractSubreg(isBigEndian ? ARM::gsub_0 : ARM::gsub_1,
+                                 SDLoc(N), MVT::i32, SDValue(CmpSwap, 0)));
   Results.push_back(SDValue(CmpSwap, 2));
 }
 
diff --git a/test/CodeGen/ARM/cmpxchg-O0-be.ll b/test/CodeGen/ARM/cmpxchg-O0-be.ll
new file mode 100644 (file)
index 0000000..9e9a93e
--- /dev/null
@@ -0,0 +1,26 @@
+; RUN: llc -verify-machineinstrs -mtriple=armebv8-linux-gnueabi -O0 %s -o - | FileCheck %s
+
+@x = global i64 10, align 8
+@y = global i64 20, align 8
+@z = global i64 20, align 8
+
+; CHECK_LABEL: main:
+; CHECK:       ldr [[R2:r[0-9]+]], {{\[}}[[R1:r[0-9]+]]{{\]}}
+; CHECK-NEXT:  ldr [[R1]], {{\[}}[[R1]], #4]
+; CHECK:       mov [[R4:r[0-9]+]], [[R2]]
+; CHECK-NEXT:  mov [[R5:r[0-9]+]], [[R1]]
+; CHECK:       ldr [[R2]], {{\[}}[[R1]]{{\]}}
+; CHECK-NEXT:  ldr [[R1]], {{\[}}[[R1]], #4]
+; CHECK:       mov [[R6:r[0-9]+]], [[R2]]
+; CHECK-NEXT:  mov [[R7:r[0-9]+]], [[R1]]
+
+define arm_aapcs_vfpcc i32 @main() #0 {
+entry:
+  %retval = alloca i32, align 4
+  store i32 0, i32* %retval, align 4
+  %0 = load i64, i64* @z, align 8
+  %1 = load i64, i64* @x, align 8
+  %2 = cmpxchg i64* @y, i64 %0, i64 %1 seq_cst seq_cst
+  %3 = extractvalue { i64, i1 } %2, 1
+  ret i32 0
+}