ARM: fix big-endian 64-bit cmpxchg.

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.

llvm-svn: 306865
This commit is contained in:
Tim Northover 2017-06-30 19:51:02 +00:00
parent b4fb256574
commit 2b5f03aa12
2 changed files with 37 additions and 4 deletions

View File

@ -7580,6 +7580,9 @@ static SDValue createGPRPairNode(SelectionDAG &DAG, SDValue V) {
SDValue VHi = DAG.getAnyExtOrTrunc( SDValue VHi = DAG.getAnyExtOrTrunc(
DAG.getNode(ISD::SRL, dl, MVT::i64, V, DAG.getConstant(32, dl, MVT::i32)), DAG.getNode(ISD::SRL, dl, MVT::i64, V, DAG.getConstant(32, dl, MVT::i32)),
dl, MVT::i32); dl, MVT::i32);
bool isBigEndian = DAG.getDataLayout().isBigEndian();
if (isBigEndian)
std::swap (VLo, VHi);
SDValue RegClass = SDValue RegClass =
DAG.getTargetConstant(ARM::GPRPairRegClassID, dl, MVT::i32); DAG.getTargetConstant(ARM::GPRPairRegClassID, dl, MVT::i32);
SDValue SubReg0 = DAG.getTargetConstant(ARM::gsub_0, 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(); MemOp[0] = cast<MemSDNode>(N)->getMemOperand();
cast<MachineSDNode>(CmpSwap)->setMemRefs(MemOp, MemOp + 1); cast<MachineSDNode>(CmpSwap)->setMemRefs(MemOp, MemOp + 1);
Results.push_back(DAG.getTargetExtractSubreg(ARM::gsub_0, SDLoc(N), MVT::i32, bool isBigEndian = DAG.getDataLayout().isBigEndian();
SDValue(CmpSwap, 0)));
Results.push_back(DAG.getTargetExtractSubreg(ARM::gsub_1, SDLoc(N), MVT::i32, Results.push_back(
SDValue(CmpSwap, 0))); 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)); Results.push_back(SDValue(CmpSwap, 2));
} }

View File

@ -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
}