Index: lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -229,8 +229,18 @@ SDValue Op2 = GetPromotedInteger(N->getOperand(2)); SDValue Op3 = GetPromotedInteger(N->getOperand(3)); - SDVTList VTs = - DAG.getVTList(Op2.getValueType(), N->getValueType(1), MVT::Other); + SDVTList VTs; + switch (N->getOpcode()){ + case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: + VTs = DAG.getVTList(Op2.getValueType(), N->getValueType(1), MVT::Other); + break; + case ISD::ATOMIC_CMP_SWAP: + VTs = DAG.getVTList(Op2.getValueType(), MVT::Other); + break; + default: + llvm_unreachable("Unknown atomic compare and swap type!"); + } + SDValue Res = DAG.getAtomicCmpSwap( N->getOpcode(), SDLoc(N), N->getMemoryVT(), VTs, N->getChain(), N->getBasePtr(), Op2, Op3, N->getMemOperand(), N->getSuccessOrdering(), Index: lib/Target/Mips/MipsISelLowering.h =================================================================== --- lib/Target/Mips/MipsISelLowering.h +++ lib/Target/Mips/MipsISelLowering.h @@ -444,6 +444,8 @@ bool IsSRA) const; SDValue lowerADD(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerATOMIC_CMP_SWAP_WITH_SUCCESS(SDValue Op, + SelectionDAG &DAG) const; /// isEligibleForTailCallOptimization - Check whether the call is eligible /// for tail call optimization. Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -396,6 +396,9 @@ setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Expand); } + setOperationAction(ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, MVT::i16, Custom); + setOperationAction(ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, MVT::i8, Custom); + setInsertFencesForAtomic(true); if (!Subtarget.hasMips32r2()) { @@ -887,6 +890,8 @@ case ISD::STORE: return lowerSTORE(Op, DAG); case ISD::ADD: return lowerADD(Op, DAG); case ISD::FP_TO_SINT: return lowerFP_TO_SINT(Op, DAG); + case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: + return lowerATOMIC_CMP_SWAP_WITH_SUCCESS(Op, DAG); } return SDValue(); } @@ -2334,6 +2339,39 @@ return DAG.getNode(ISD::BITCAST, SDLoc(Op), Op.getValueType(), Trunc); } +/// Lower ATOMIC_CMP_SWAP_WITH_SUCCESS to ATOMIC_CMP_SWAP and +/// SETCC with sign extended operands. ATOMIC_CMP_SWAP for MIPS gives +/// back a sign extended result. +SDValue +MipsTargetLowering::lowerATOMIC_CMP_SWAP_WITH_SUCCESS(SDValue Op, + SelectionDAG &DAG) const { + + if (Op.getOperand(2).getValueType() != MVT::i16 && + Op.getOperand(2).getValueType() != MVT::i8) + return Op; + + AtomicSDNode * RefNode = cast(Op); + EVT Type = Op.getValueType(); + SDLoc DL(Op); + SDVTList VTs = DAG.getVTList(RefNode->getValueType(0) , MVT::Other); + SDValue AtomicCmpSwp = + DAG.getAtomicCmpSwap( + ISD::ATOMIC_CMP_SWAP, DL, RefNode->getMemoryVT(), VTs, + RefNode->getOperand(0), RefNode->getOperand(1), RefNode->getOperand(2), + RefNode->getOperand(3), cast(Op)->getMemOperand(), + RefNode->getSuccessOrdering(), + RefNode->getFailureOrdering(), + RefNode->getSynchScope()); + + SDValue SextOp = DAG.getSExtOrTrunc(Op.getOperand(2), SDLoc(Op), Type); + SDValue SetCC = DAG.getSetCC(SDLoc(Op), Type, AtomicCmpSwp, SextOp, ISD::SETEQ); + SDValue ZextRes = DAG.getZExtOrTrunc(SetCC, SDLoc(Op), MVT::i1); + + SDValue Ops[3] = {AtomicCmpSwp, ZextRes, RefNode->getChain()}; + SDValue Ret = DAG.getMergeValues(Ops, SDLoc(Op)); + return Ret; +} + //===----------------------------------------------------------------------===// // Calling Convention Implementation //===----------------------------------------------------------------------===// Index: test/CodeGen/Mips/atomic.ll =================================================================== --- test/CodeGen/Mips/atomic.ll +++ test/CodeGen/Mips/atomic.ll @@ -358,9 +358,15 @@ ; NO-SEB-SEH: sra $[[R19:[0-9]+]], $[[R18]], 24 ; HAS-SEB-SEH: seb $[[R19:[0-9]+]], $[[R17]] +; NOT-MICROMIPS: andi $[[R20:[0-9]+]], $[[R19]], 255 -; ALL: xor $[[R20:[0-9]+]], $[[R19]], $5 -; ALL: sltiu $2, $[[R20]], 1 +; NOT-MICROMIPS: xor $[[R21:[0-9]+]], $[[R20]], $[[R9]] +; NOT-MICROMIPS: sltiu $2, $[[R21]], 1 + +; MICROMIPS: andi16 $[[R20:[0-9]+]], $[[R19]], 255 +; MICROMIPS: andi16 $[[R21:[0-9]+]], $5, 255 +; MICROMIPS: xor $[[R22:[0-9]+]], $[[R20]], $[[R21]] +; MICROMIPS: sltiu $2, $[[R22]], 1 } ; Check one i16 so that we cover the seh sign extend @@ -407,6 +413,49 @@ ; MIPS32R2: seh $2, $[[R16]] } +; Test that the i16 return value from cmpxchg is recognised as signed, +; so that setCC doesn't end up comparing an unsigned value to a signed +; value. +; The rest of the functions here are testing the atomic expansion, so +; we just match the end of the function. +define {i16, i1} @foo(i16* %addr, i16 %l, i16 %r, i16 %new) { + %desired = add i16 %l, %r + %res = cmpxchg i16* %addr, i16 %desired, i16 %new seq_cst seq_cst + ret {i16, i1} %res + +; ALL-LABEL: foo +; MIPSR6: addu $[[R2:[0-9]+]], $[[R1:[0-9]+]], $[[R0:[0-9]+]] +; MIPSR6: andi $[[R3:[0-9]+]], $[[R2]], 65535 +; NOT-MICROMIPS: addu $[[R2:[0-9]+]], $[[R1:[0-9]+]], $[[R0:[0-9]+]] +; NOT-MICROMIPS: andi $[[R3:[0-9]+]], $[[R2]], 65535 +; MICROMIPS: addu16 $[[R2:[0-9]+]], $[[R1:[0-9]+]], $[[R0:[0-9]+]] +; MICROMIPS: andi16 $[[R3:[0-9]+]], $[[R2]], 65535 + +; ALL: sync + +; ALL: $[[BB0:[A-Z_0-9]+]]: +; ALL: ll $[[R4:[0-9]+]], 0($[[R5:[0-9]+]]) +; ALL: and $[[R6:[0-9]+]], $[[R4]], $ +; ALL: and $[[R7:[0-9]+]], $[[R4]], $ +; ALL: or $[[R8:[0-9]+]], $[[R7]], $ +; ALL: sc $[[R8]], 0($[[R5]]) +; NOT-MICROMIPS: beqz $[[R8]], $[[BB0]] +; MICROMIPS: beqzc $[[R8]], $[[BB0]] +; MIPSR6: beqzc $[[R8]], $[[BB0]] + +; ALL $[[BB1:[A-Z_0-9]+]]: +; ALL: srlv $[[R9:[0-9]+]], $[[R6]], $ + +; NO-SEB-SEH: sll $[[RA:[0-9]+]], $[[R9]], 16 +; NO-SEB-SEH: sra $[[R10:[0-9]+]], $[[RA]], 16 + +; HAS-SEB-SEH: seh $[[R10:[0-9]+]], $[[R9]] +; NOT-MICROMIPS: andi $[[R11:[0-9]+]], $[[R10]], 65535 +; MICROMIPS: andi16 $[[R11:[0-9]+]], $[[R10]], 65535 +; ALL: xor $[[R12:[0-9]+]], $[[R11]], $[[R3]] +; ALL: sltiu $3, $[[R12]], 1 +; ALL: sync +} @countsint = common global i32 0, align 4