Index: llvm/trunk/include/llvm/Target/TargetLowering.h =================================================================== --- llvm/trunk/include/llvm/Target/TargetLowering.h +++ llvm/trunk/include/llvm/Target/TargetLowering.h @@ -1248,9 +1248,10 @@ 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; } /// @} Index: llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -2837,25 +2837,38 @@ 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; Index: llvm/trunk/lib/Target/Mips/MipsISelLowering.h =================================================================== --- llvm/trunk/lib/Target/Mips/MipsISelLowering.h +++ llvm/trunk/lib/Target/Mips/MipsISelLowering.h @@ -238,8 +238,8 @@ 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, Index: llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.h =================================================================== --- llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.h +++ llvm/trunk/lib/Target/SystemZ/SystemZISelLowering.h @@ -459,6 +459,10 @@ 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; } Index: llvm/trunk/test/CodeGen/SystemZ/cmpxchg-05.ll =================================================================== --- llvm/trunk/test/CodeGen/SystemZ/cmpxchg-05.ll +++ llvm/trunk/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 +}