From: Marcin Koscielnicki Date: Tue, 10 May 2016 16:49:04 +0000 (+0000) Subject: [PR27599] [SystemZ] [SelectionDAG] Fix extension of atomic cmpxchg result. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9100579a4f8d8c9c76305a71f623253d59f1a043;p=llvm [PR27599] [SystemZ] [SelectionDAG] Fix extension of atomic cmpxchg result. Currently, SelectionDAG assumes 8/16-bit cmpxchg returns either a sign extended result, or a zero extended result. SystemZ takes a third option by returning junk in the high bits (rotated contents of the other bytes in the memory word). In that case, don't use Assert*ext, and zero-extend the result ourselves if a comparison is needed. Differential Revision: http://reviews.llvm.org/D19800 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@269075 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index c47e3c0d963..b0002b512c4 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -1248,9 +1248,10 @@ public: return nullptr; } - /// Returns true if the platform's atomic operations are sign extended. - virtual bool hasSignExtendedAtomicOps() const { - return false; + /// Returns how the platform's atomic operations are extended (ZERO_EXTEND, + /// SIGN_EXTEND, or ANY_EXTEND). + virtual ISD::NodeType getExtendForAtomicOps() const { + return ISD::ZERO_EXTEND; } /// @} diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index a06932b0521..b8918d21fc9 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -2837,25 +2837,38 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) { cast(Node)->getFailureOrdering(), cast(Node)->getSynchScope()); + SDValue ExtRes = Res; SDValue LHS = Res; SDValue RHS = Node->getOperand(1); EVT AtomicType = cast(Node)->getMemoryVT(); EVT OuterType = Node->getValueType(0); - if (TLI.hasSignExtendedAtomicOps()) { + switch (TLI.getExtendForAtomicOps()) { + case ISD::SIGN_EXTEND: LHS = DAG.getNode(ISD::AssertSext, dl, OuterType, Res, DAG.getValueType(AtomicType)); RHS = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, OuterType, Node->getOperand(2), DAG.getValueType(AtomicType)); - } else { - LHS = DAG.getNode(ISD::AssertZext, dl, OuterType, Res, DAG.getValueType(AtomicType)); + ExtRes = LHS; + break; + case ISD::ZERO_EXTEND: + LHS = DAG.getNode(ISD::AssertZext, dl, OuterType, Res, + DAG.getValueType(AtomicType)); RHS = DAG.getNode(ISD::ZERO_EXTEND, dl, OuterType, Node->getOperand(2)); + ExtRes = LHS; + break; + case ISD::ANY_EXTEND: + LHS = DAG.getZeroExtendInReg(Res, dl, AtomicType); + RHS = DAG.getNode(ISD::ZERO_EXTEND, dl, OuterType, Node->getOperand(2)); + break; + default: + llvm_unreachable("Invalid atomic op extension"); } SDValue Success = DAG.getSetCC(dl, Node->getValueType(1), LHS, RHS, ISD::SETEQ); - Results.push_back(LHS.getValue(0)); + Results.push_back(ExtRes.getValue(0)); Results.push_back(Success); Results.push_back(Res.getValue(1)); break; diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 31ae235ab45..a56918c0519 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -238,8 +238,8 @@ namespace llvm { bool isCheapToSpeculateCttz() const override; bool isCheapToSpeculateCtlz() const override; - bool hasSignExtendedAtomicOps() const override { - return true; + ISD::NodeType getExtendForAtomicOps() const override { + return ISD::SIGN_EXTEND; } void LowerOperationWrapper(SDNode *N, diff --git a/lib/Target/SystemZ/SystemZISelLowering.h b/lib/Target/SystemZ/SystemZISelLowering.h index f26e1dc0d66..bfd08543563 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.h +++ b/lib/Target/SystemZ/SystemZISelLowering.h @@ -459,6 +459,10 @@ public: SelectionDAG &DAG) const override; SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; + ISD::NodeType getExtendForAtomicOps() const override { + return ISD::ANY_EXTEND; + } + bool supportSwiftError() const override { return true; } diff --git a/test/CodeGen/SystemZ/cmpxchg-05.ll b/test/CodeGen/SystemZ/cmpxchg-05.ll new file mode 100644 index 00000000000..68261efa638 --- /dev/null +++ b/test/CodeGen/SystemZ/cmpxchg-05.ll @@ -0,0 +1,81 @@ +; Test proper extension of 8-bit/16-bit cmpxchg. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; CHECK-LABEL: f1 +; CHECK: crjlh +; CHECK-NOT: llcr +; CHECK-NOT: cr +; CHECK: llgcr %r2, [[RES:%r[0-9]+]] +; CHECK-NOT: llcr +; CHECK-NOT: cr +define zeroext i8 @f1(i8* nocapture, i8 zeroext, i8 zeroext) { + %cx = cmpxchg i8* %0, i8 %1, i8 %2 seq_cst seq_cst + %res = extractvalue { i8, i1 } %cx, 0 + ret i8 %res +} + +; CHECK-LABEL: f2 +; CHECK: crjlh +; CHECK-NOT: llhr +; CHECK-NOT: cr +; CHECK: llghr %r2, [[RES:%r[0-9]+]] +; CHECK-NOT: llhr +; CHECK-NOT: cr +define zeroext i16 @f2(i16* nocapture, i16 zeroext, i16 zeroext) { + %cx = cmpxchg i16* %0, i16 %1, i16 %2 seq_cst seq_cst + %res = extractvalue { i16, i1 } %cx, 0 + ret i16 %res +} + +; CHECK-LABEL: f3 +; CHECK: crjlh +; CHECK-NOT: llcr +; CHECK-NOT: cr +; CHECK: lgbr %r2, [[RES:%r[0-9]+]] +; CHECK-NOT: llcr +; CHECK-NOT: cr +define signext i8 @f3(i8* nocapture, i8 signext, i8 signext) { + %cx = cmpxchg i8* %0, i8 %1, i8 %2 seq_cst seq_cst + %res = extractvalue { i8, i1 } %cx, 0 + ret i8 %res +} + +; CHECK-LABEL: f4 +; CHECK: crjlh +; CHECK-NOT: llhr +; CHECK-NOT: cr +; CHECK: lghr %r2, [[RES:%r[0-9]+]] +; CHECK-NOT: llhr +; CHECK-NOT: cr +define signext i16 @f4(i16* nocapture, i16 signext, i16 signext) { + %cx = cmpxchg i16* %0, i16 %1, i16 %2 seq_cst seq_cst + %res = extractvalue { i16, i1 } %cx, 0 + ret i16 %res +} + +; Now use the comparison result. +; CHECK-LABEL: f5 +; CHECK: llcr [[REG:%r[0-9]+]], [[RES:%r[0-9]+]] +; CHECK: cr [[REG]], %r3 +define zeroext i8 @f5(i8* nocapture, i8 zeroext, i8 zeroext) { + %cx = cmpxchg i8* %0, i8 %1, i8 %2 seq_cst seq_cst + %res = extractvalue { i8, i1 } %cx, 1 + %xres = sext i1 %res to i8 + ret i8 %xres +} + +; Now use the comparison result and zero-extended old value. +; CHECK-LABEL: f6 +; CHECK: llcr [[REG:%r[0-9]+]], [[RES:%r[0-9]+]] +; CHECK: st [[REG]], 0(%r5) +; CHECK: cr [[REG]], %r3 +define zeroext i8 @f6(i8* nocapture, i8 zeroext, i8 zeroext, i32*) { + %cx = cmpxchg i8* %0, i8 %1, i8 %2 seq_cst seq_cst + %old = extractvalue { i8, i1 } %cx, 0 + %xold = zext i8 %old to i32 + store i32 %xold, i32* %3 + %res = extractvalue { i8, i1 } %cx, 1 + %xres = sext i1 %res to i8 + ret i8 %xres +}