forked from OSchip/llvm-project
[OpenMP][IRBuilder] Fix emitAtomicUpdate conditions
This patch fixes the condition for emitting atomic update using `atomicrmw` instruction or compare-exchange loop. Reviewed By: ftynse Differential Revision: https://reviews.llvm.org/D121546
This commit is contained in:
parent
65cf643073
commit
423e3edc27
|
@ -3584,13 +3584,25 @@ std::pair<Value *, Value *> OpenMPIRBuilder::emitAtomicUpdate(
|
|||
AtomicUpdateCallbackTy &UpdateOp, bool VolatileX, bool IsXBinopExpr) {
|
||||
// TODO: handle the case where XElemTy is not byte-sized or not a power of 2
|
||||
// or a complex datatype.
|
||||
bool DoCmpExch = (RMWOp == AtomicRMWInst::BAD_BINOP) ||
|
||||
(RMWOp == AtomicRMWInst::FAdd) ||
|
||||
(RMWOp == AtomicRMWInst::FSub) ||
|
||||
(RMWOp == AtomicRMWInst::Sub && !IsXBinopExpr) || !XElemTy;
|
||||
bool emitRMWOp = false;
|
||||
switch (RMWOp) {
|
||||
case AtomicRMWInst::Add:
|
||||
case AtomicRMWInst::And:
|
||||
case AtomicRMWInst::Nand:
|
||||
case AtomicRMWInst::Or:
|
||||
case AtomicRMWInst::Xor:
|
||||
emitRMWOp = XElemTy;
|
||||
break;
|
||||
case AtomicRMWInst::Sub:
|
||||
emitRMWOp = (IsXBinopExpr && XElemTy);
|
||||
break;
|
||||
default:
|
||||
emitRMWOp = false;
|
||||
}
|
||||
emitRMWOp &= XElemTy->isIntegerTy();
|
||||
|
||||
std::pair<Value *, Value *> Res;
|
||||
if (XElemTy->isIntegerTy() && !DoCmpExch) {
|
||||
if (emitRMWOp) {
|
||||
Res.first = Builder.CreateAtomicRMW(RMWOp, X, Expr, llvm::MaybeAlign(), AO);
|
||||
// not needed except in case of postfix captures. Generate anyway for
|
||||
// consistency with the else part. Will be removed with any DCE pass.
|
||||
|
|
|
@ -3167,6 +3167,73 @@ TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdateFloat) {
|
|||
EXPECT_FALSE(verifyModule(*M, &errs()));
|
||||
}
|
||||
|
||||
TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdateIntr) {
|
||||
OpenMPIRBuilder OMPBuilder(*M);
|
||||
OMPBuilder.initialize();
|
||||
F->setName("func");
|
||||
IRBuilder<> Builder(BB);
|
||||
|
||||
OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
|
||||
|
||||
Type *IntTy = Type::getInt32Ty(M->getContext());
|
||||
AllocaInst *XVal = Builder.CreateAlloca(IntTy);
|
||||
XVal->setName("AtomicVar");
|
||||
Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0), XVal);
|
||||
OpenMPIRBuilder::AtomicOpValue X = {XVal, IntTy, false, false};
|
||||
AtomicOrdering AO = AtomicOrdering::Monotonic;
|
||||
Constant *ConstVal = ConstantInt::get(Type::getInt32Ty(Ctx), 1);
|
||||
Value *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1);
|
||||
AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::UMax;
|
||||
bool IsXLHSInRHSPart = false;
|
||||
|
||||
BasicBlock *EntryBB = BB;
|
||||
OpenMPIRBuilder::InsertPointTy AllocaIP(EntryBB,
|
||||
EntryBB->getFirstInsertionPt());
|
||||
Value *Sub = nullptr;
|
||||
|
||||
auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) {
|
||||
Sub = IRB.CreateSub(ConstVal, Atomic);
|
||||
return Sub;
|
||||
};
|
||||
Builder.restoreIP(OMPBuilder.createAtomicUpdate(
|
||||
Builder, AllocaIP, X, Expr, AO, RMWOp, UpdateOp, IsXLHSInRHSPart));
|
||||
BasicBlock *ContBB = EntryBB->getSingleSuccessor();
|
||||
BranchInst *ContTI = dyn_cast<BranchInst>(ContBB->getTerminator());
|
||||
EXPECT_NE(ContTI, nullptr);
|
||||
BasicBlock *EndBB = ContTI->getSuccessor(0);
|
||||
EXPECT_TRUE(ContTI->isConditional());
|
||||
EXPECT_EQ(ContTI->getSuccessor(1), ContBB);
|
||||
EXPECT_NE(EndBB, nullptr);
|
||||
|
||||
PHINode *Phi = dyn_cast<PHINode>(&ContBB->front());
|
||||
EXPECT_NE(Phi, nullptr);
|
||||
EXPECT_EQ(Phi->getNumIncomingValues(), 2U);
|
||||
EXPECT_EQ(Phi->getIncomingBlock(0), EntryBB);
|
||||
EXPECT_EQ(Phi->getIncomingBlock(1), ContBB);
|
||||
|
||||
EXPECT_EQ(Sub->getNumUses(), 1U);
|
||||
StoreInst *St = dyn_cast<StoreInst>(Sub->user_back());
|
||||
AllocaInst *UpdateTemp = dyn_cast<AllocaInst>(St->getPointerOperand());
|
||||
|
||||
ExtractValueInst *ExVI1 =
|
||||
dyn_cast<ExtractValueInst>(Phi->getIncomingValueForBlock(ContBB));
|
||||
EXPECT_NE(ExVI1, nullptr);
|
||||
AtomicCmpXchgInst *CmpExchg =
|
||||
dyn_cast<AtomicCmpXchgInst>(ExVI1->getAggregateOperand());
|
||||
EXPECT_NE(CmpExchg, nullptr);
|
||||
EXPECT_EQ(CmpExchg->getPointerOperand(), XVal);
|
||||
EXPECT_EQ(CmpExchg->getCompareOperand(), Phi);
|
||||
EXPECT_EQ(CmpExchg->getSuccessOrdering(), AtomicOrdering::Monotonic);
|
||||
|
||||
LoadInst *Ld = dyn_cast<LoadInst>(CmpExchg->getNewValOperand());
|
||||
EXPECT_NE(Ld, nullptr);
|
||||
EXPECT_EQ(UpdateTemp, Ld->getPointerOperand());
|
||||
|
||||
Builder.CreateRetVoid();
|
||||
OMPBuilder.finalize();
|
||||
EXPECT_FALSE(verifyModule(*M, &errs()));
|
||||
}
|
||||
|
||||
TEST_F(OpenMPIRBuilderTest, OMPAtomicCapture) {
|
||||
OpenMPIRBuilder OMPBuilder(*M);
|
||||
OMPBuilder.initialize();
|
||||
|
|
|
@ -1049,6 +1049,15 @@ llvm.func @omp_atomic_update_intrinsic(%x:!llvm.ptr<i32>, %expr: i32) {
|
|||
%newval = "llvm.intr.smax"(%xval, %expr) : (i32, i32) -> i32
|
||||
omp.yield(%newval : i32)
|
||||
}
|
||||
// CHECK: %[[t1:.*]] = call i32 @llvm.umax.i32(i32 %[[x_old:.*]], i32 %[[expr]])
|
||||
// CHECK: store i32 %[[t1]], i32* %[[x_new:.*]]
|
||||
// CHECK: %[[t2:.*]] = load i32, i32* %[[x_new]]
|
||||
// CHECK: cmpxchg i32* %[[x]], i32 %[[x_old]], i32 %[[t2]]
|
||||
omp.atomic.update %x : !llvm.ptr<i32> {
|
||||
^bb0(%xval: i32):
|
||||
%newval = "llvm.intr.umax"(%xval, %expr) : (i32, i32) -> i32
|
||||
omp.yield(%newval : i32)
|
||||
}
|
||||
llvm.return
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue