Index: llvm/trunk/lib/CodeGen/AtomicExpandPass.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AtomicExpandPass.cpp +++ llvm/trunk/lib/CodeGen/AtomicExpandPass.cpp @@ -88,6 +88,7 @@ void expandPartwordAtomicRMW( AtomicRMWInst *I, TargetLoweringBase::AtomicExpansionKind ExpansionKind); + AtomicRMWInst *widenPartwordAtomicRMW(AtomicRMWInst *AI); void expandPartwordCmpXchg(AtomicCmpXchgInst *I); AtomicCmpXchgInst *convertCmpXchgToIntegerType(AtomicCmpXchgInst *CI); @@ -306,6 +307,16 @@ if (isIdempotentRMW(RMWI) && simplifyIdempotentRMW(RMWI)) { MadeChange = true; } else { + unsigned MinCASSize = TLI->getMinCmpXchgSizeInBits() / 8; + unsigned ValueSize = getAtomicOpSize(RMWI); + AtomicRMWInst::BinOp Op = RMWI->getOperation(); + if (ValueSize < MinCASSize && + (Op == AtomicRMWInst::Or || Op == AtomicRMWInst::Xor || + Op == AtomicRMWInst::And)) { + RMWI = widenPartwordAtomicRMW(RMWI); + MadeChange = true; + } + MadeChange |= tryExpandAtomicRMW(RMWI); } } else if (CASI) { @@ -659,12 +670,10 @@ } case AtomicRMWInst::Or: case AtomicRMWInst::Xor: - // Or/Xor won't affect any other bits, so can just be done - // directly. - return performAtomicOp(Op, Builder, Loaded, Shifted_Inc); + case AtomicRMWInst::And: + llvm_unreachable("Or/Xor/And handled by widenPartwordAtomicRMW"); case AtomicRMWInst::Add: case AtomicRMWInst::Sub: - case AtomicRMWInst::And: case AtomicRMWInst::Nand: { // The other arithmetic ops need to be masked into place. Value *NewVal = performAtomicOp(Op, Builder, Loaded, Shifted_Inc); @@ -733,6 +742,41 @@ AI->eraseFromParent(); } +// Widen the bitwise atomicrmw (or/xor/and) to the minimum supported width. +AtomicRMWInst *AtomicExpand::widenPartwordAtomicRMW(AtomicRMWInst *AI) { + IRBuilder<> Builder(AI); + AtomicRMWInst::BinOp Op = AI->getOperation(); + + assert((Op == AtomicRMWInst::Or || Op == AtomicRMWInst::Xor || + Op == AtomicRMWInst::And) && + "Unable to widen operation"); + + PartwordMaskValues PMV = + createMaskInstrs(Builder, AI, AI->getType(), AI->getPointerOperand(), + TLI->getMinCmpXchgSizeInBits() / 8); + + Value *ValOperand_Shifted = + Builder.CreateShl(Builder.CreateZExt(AI->getValOperand(), PMV.WordType), + PMV.ShiftAmt, "ValOperand_Shifted"); + + Value *NewOperand; + + if (Op == AtomicRMWInst::And) + NewOperand = + Builder.CreateOr(PMV.Inv_Mask, ValOperand_Shifted, "AndOperand"); + else + NewOperand = ValOperand_Shifted; + + AtomicRMWInst *NewAI = Builder.CreateAtomicRMW(Op, PMV.AlignedAddr, + NewOperand, AI->getOrdering()); + + Value *FinalOldResult = Builder.CreateTrunc( + Builder.CreateLShr(NewAI, PMV.ShiftAmt), PMV.ValueType); + AI->replaceAllUsesWith(FinalOldResult); + AI->eraseFromParent(); + return NewAI; +} + void AtomicExpand::expandPartwordCmpXchg(AtomicCmpXchgInst *CI) { // The basic idea here is that we're expanding a cmpxchg of a // smaller memory size up to a word-sized cmpxchg. To do this, we Index: llvm/trunk/test/Transforms/AtomicExpand/SPARC/partword.ll =================================================================== --- llvm/trunk/test/Transforms/AtomicExpand/SPARC/partword.ll +++ llvm/trunk/test/Transforms/AtomicExpand/SPARC/partword.ll @@ -147,6 +147,31 @@ ret i16 %ret } +; CHECK-LABEL: @test_or_i16( +; (I'm going to just assert on the bits that differ from add, above.) +; CHECK:atomicrmw.start: +; CHECK: %new = or i32 %loaded, %ValOperand_Shifted +; CHECK: %6 = cmpxchg i32* %AlignedAddr, i32 %loaded, i32 %new monotonic monotonic +; CHECK:atomicrmw.end: +define i16 @test_or_i16(i16* %arg, i16 %val) { +entry: + %ret = atomicrmw or i16* %arg, i16 %val seq_cst + ret i16 %ret +} + +; CHECK-LABEL: @test_and_i16( +; (I'm going to just assert on the bits that differ from add, above.) +; CHECK: %AndOperand = or i32 %Inv_Mask, %ValOperand_Shifted +; CHECK:atomicrmw.start: +; CHECK: %new = and i32 %loaded, %AndOperand +; CHECK: %6 = cmpxchg i32* %AlignedAddr, i32 %loaded, i32 %new monotonic monotonic +; CHECK:atomicrmw.end: +define i16 @test_and_i16(i16* %arg, i16 %val) { +entry: + %ret = atomicrmw and i16* %arg, i16 %val seq_cst + ret i16 %ret +} + ; CHECK-LABEL: @test_min_i16( ; CHECK:atomicrmw.start: ; CHECK: %6 = lshr i32 %loaded, %ShiftAmt