[clang] eb673be - [OMPIRBuilder] Add the support for compare capture
Shilei Tian via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 1 16:53:47 PDT 2022
Author: Shilei Tian
Date: 2022-06-01T19:53:43-04:00
New Revision: eb673be5ac8510646692f82a606a1f2c10f24828
URL: https://github.com/llvm/llvm-project/commit/eb673be5ac8510646692f82a606a1f2c10f24828
DIFF: https://github.com/llvm/llvm-project/commit/eb673be5ac8510646692f82a606a1f2c10f24828.diff
LOG: [OMPIRBuilder] Add the support for compare capture
This patch adds the support for `compare capture` in `OMPIRBuilder`.
Reviewed By: jdoerfert
Differential Revision: https://reviews.llvm.org/D120007
Added:
Modified:
clang/lib/CodeGen/CGStmtOpenMP.cpp
llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index f78443fd20bc..b22b278202dc 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -6190,9 +6190,11 @@ static void emitOMPAtomicCompareExpr(CodeGenFunction &CGF,
XAddr.getPointer(), XAddr.getElementType(),
X->getType()->hasSignedIntegerRepresentation(),
X->getType().isVolatileQualified()};
+ llvm::OpenMPIRBuilder::AtomicOpValue VOpVal, ROpVal;
CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
- CGF.Builder, XOpVal, EVal, DVal, AO, Op, IsXBinopExpr));
+ CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
+ /* IsPostfixUpdate */ false, /* IsFailOnly */ false));
}
static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
index 93b1297a7930..c0f3020201d5 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
@@ -1462,7 +1462,7 @@ class OpenMPIRBuilder {
bool IsPostfixUpdate, bool IsXBinopExpr);
/// Emit atomic compare for constructs: --- Only scalar data types
- /// cond-update-atomic:
+ /// cond-expr-stmt:
/// x = x ordop expr ? expr : x;
/// x = expr ordop x ? expr : x;
/// x = x == e ? d : x;
@@ -1472,9 +1472,21 @@ class OpenMPIRBuilder {
/// if (expr ordop x) { x = expr; }
/// if (x == e) { x = d; }
/// if (e == x) { x = d; } (this one is not in the spec)
+ /// conditional-update-capture-atomic:
+ /// v = x; cond-update-stmt; (IsPostfixUpdate=true, IsFailOnly=false)
+ /// cond-update-stmt; v = x; (IsPostfixUpdate=false, IsFailOnly=false)
+ /// if (x == e) { x = d; } else { v = x; } (IsPostfixUpdate=false,
+ /// IsFailOnly=true)
+ /// r = x == e; if (r) { x = d; } (IsPostfixUpdate=false, IsFailOnly=false)
+ /// r = x == e; if (r) { x = d; } else { v = x; } (IsPostfixUpdate=false,
+ /// IsFailOnly=true)
///
/// \param Loc The insert and source location description.
/// \param X The target atomic pointer to be updated.
+ /// \param V Memory address where to store captured value (for
+ /// compare capture only).
+ /// \param R Memory address where to store comparison result
+ /// (for compare capture with '==' only).
/// \param E The expected value ('e') for forms that use an
/// equality comparison or an expression ('expr') for
/// forms that use 'ordop' (logically an atomic maximum or
@@ -1486,13 +1498,19 @@ class OpenMPIRBuilder {
/// \param Op Atomic compare operation. It can only be ==, <, or >.
/// \param IsXBinopExpr True if the conditional statement is in the form where
/// x is on LHS. It only matters for < or >.
+ /// \param IsPostfixUpdate True if original value of 'x' must be stored in
+ /// 'v', not an updated one (for compare capture
+ /// only).
+ /// \param IsFailOnly True if the original value of 'x' is stored to 'v'
+ /// only when the comparison fails. This is only valid for
+ /// the case the comparison is '=='.
///
/// \return Insertion point after generated atomic capture IR.
- InsertPointTy createAtomicCompare(const LocationDescription &Loc,
- AtomicOpValue &X, Value *E, Value *D,
- AtomicOrdering AO,
- omp::OMPAtomicCompareOp Op,
- bool IsXBinopExpr);
+ InsertPointTy
+ createAtomicCompare(const LocationDescription &Loc, AtomicOpValue &X,
+ AtomicOpValue &V, AtomicOpValue &R, Value *E, Value *D,
+ AtomicOrdering AO, omp::OMPAtomicCompareOp Op,
+ bool IsXBinopExpr, bool IsPostfixUpdate, bool IsFailOnly);
/// Create the control flow structure of a canonical OpenMP loop.
///
diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index dfa20d4cabd1..a4aa69ad2a04 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -4108,8 +4108,11 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicCapture(
}
OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicCompare(
- const LocationDescription &Loc, AtomicOpValue &X, Value *E, Value *D,
- AtomicOrdering AO, OMPAtomicCompareOp Op, bool IsXBinopExpr) {
+ const LocationDescription &Loc, AtomicOpValue &X, AtomicOpValue &V,
+ AtomicOpValue &R, Value *E, Value *D, AtomicOrdering AO,
+ omp::OMPAtomicCompareOp Op, bool IsXBinopExpr, bool IsPostfixUpdate,
+ bool IsFailOnly) {
+
if (!updateToLocation(Loc))
return Loc.IP;
@@ -4117,14 +4120,80 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicCompare(
"OMP atomic expects a pointer to target memory");
assert((X.ElemTy->isIntegerTy() || X.ElemTy->isPointerTy()) &&
"OMP atomic compare expected a integer scalar type");
+ // compare capture
+ if (V.Var) {
+ assert(V.Var->getType()->isPointerTy() && "v.var must be of pointer type");
+ assert(V.ElemTy == X.ElemTy && "x and v must be of same type");
+ }
if (Op == OMPAtomicCompareOp::EQ) {
AtomicOrdering Failure = AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
- // We don't need the result for now.
- (void)Builder.CreateAtomicCmpXchg(X.Var, E, D, MaybeAlign(), AO, Failure);
+ AtomicCmpXchgInst *Result =
+ Builder.CreateAtomicCmpXchg(X.Var, E, D, MaybeAlign(), AO, Failure);
+ if (V.Var) {
+ Value *OldValue = Builder.CreateExtractValue(Result, /*Idxs=*/0);
+ assert(OldValue->getType() == V.ElemTy &&
+ "OldValue and V must be of same type");
+ if (IsPostfixUpdate) {
+ Builder.CreateStore(OldValue, V.Var, V.IsVolatile);
+ } else {
+ Value *SuccessOrFail = Builder.CreateExtractValue(Result, /*Idxs=*/1);
+ if (IsFailOnly) {
+ // CurBB----
+ // | |
+ // v |
+ // ContBB |
+ // | |
+ // v |
+ // ExitBB <-
+ //
+ // where ContBB only contains the store of old value to 'v'.
+ BasicBlock *CurBB = Builder.GetInsertBlock();
+ Instruction *CurBBTI = CurBB->getTerminator();
+ CurBBTI = CurBBTI ? CurBBTI : Builder.CreateUnreachable();
+ BasicBlock *ExitBB = CurBB->splitBasicBlock(
+ CurBBTI, X.Var->getName() + ".atomic.exit");
+ BasicBlock *ContBB = CurBB->splitBasicBlock(
+ CurBB->getTerminator(), X.Var->getName() + ".atomic.cont");
+ ContBB->getTerminator()->eraseFromParent();
+ CurBB->getTerminator()->eraseFromParent();
+
+ Builder.CreateCondBr(SuccessOrFail, ExitBB, ContBB);
+
+ Builder.SetInsertPoint(ContBB);
+ Builder.CreateStore(OldValue, V.Var);
+ Builder.CreateBr(ExitBB);
+
+ if (UnreachableInst *ExitTI =
+ dyn_cast<UnreachableInst>(ExitBB->getTerminator())) {
+ CurBBTI->eraseFromParent();
+ Builder.SetInsertPoint(ExitBB);
+ } else {
+ Builder.SetInsertPoint(ExitTI);
+ }
+ } else {
+ Value *CapturedValue =
+ Builder.CreateSelect(SuccessOrFail, E, OldValue);
+ Builder.CreateStore(CapturedValue, V.Var, V.IsVolatile);
+ }
+ }
+ }
+ // The comparison result has to be stored.
+ if (R.Var) {
+ assert(R.Var->getType()->isPointerTy() &&
+ "r.var must be of pointer type");
+ assert(R.ElemTy->isIntegerTy() && "r must be of integral type");
+
+ Value *SuccessFailureVal = Builder.CreateExtractValue(Result, /*Idxs=*/1);
+ Value *ResultCast = R.IsSigned
+ ? Builder.CreateSExt(SuccessFailureVal, R.ElemTy)
+ : Builder.CreateZExt(SuccessFailureVal, R.ElemTy);
+ Builder.CreateStore(ResultCast, R.Var, R.IsVolatile);
+ }
} else {
assert((Op == OMPAtomicCompareOp::MAX || Op == OMPAtomicCompareOp::MIN) &&
"Op should be either max or min at this point");
+ assert(!IsFailOnly && "IsFailOnly is only valid when the comparison is ==");
// Reverse the ordop as the OpenMP forms are
diff erent from LLVM forms.
// Let's take max as example.
@@ -4150,8 +4219,36 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicCompare(
NewOp = Op == OMPAtomicCompareOp::MAX ? AtomicRMWInst::UMax
: AtomicRMWInst::UMin;
}
- // We dont' need the result for now.
- (void)Builder.CreateAtomicRMW(NewOp, X.Var, E, MaybeAlign(), AO);
+
+ AtomicRMWInst *OldValue =
+ Builder.CreateAtomicRMW(NewOp, X.Var, E, MaybeAlign(), AO);
+ if (V.Var) {
+ Value *CapturedValue = nullptr;
+ if (IsPostfixUpdate) {
+ CapturedValue = OldValue;
+ } else {
+ CmpInst::Predicate Pred;
+ switch (NewOp) {
+ case AtomicRMWInst::Max:
+ Pred = CmpInst::ICMP_SGT;
+ break;
+ case AtomicRMWInst::UMax:
+ Pred = CmpInst::ICMP_UGT;
+ break;
+ case AtomicRMWInst::Min:
+ Pred = CmpInst::ICMP_SLT;
+ break;
+ case AtomicRMWInst::UMin:
+ Pred = CmpInst::ICMP_ULT;
+ break;
+ default:
+ llvm_unreachable("unexpected comparison op");
+ }
+ Value *NonAtomicCmp = Builder.CreateCmp(Pred, OldValue, E);
+ CapturedValue = Builder.CreateSelect(NonAtomicCmp, E, OldValue);
+ }
+ Builder.CreateStore(CapturedValue, V.Var, V.IsVolatile);
+ }
}
checkAndEmitFlushAfterAtomic(Loc, AO, AtomicKind::Compare);
diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
index aef5992c93ea..331f6a04850c 100644
--- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
@@ -3475,18 +3475,21 @@ TEST_F(OpenMPIRBuilderTest, OMPAtomicCompare) {
OpenMPIRBuilder::AtomicOpValue XSigned = {XVal, Int32, true, false};
OpenMPIRBuilder::AtomicOpValue XUnsigned = {XVal, Int32, false, false};
+ // V and R are not used in atomic compare
+ OpenMPIRBuilder::AtomicOpValue V = {nullptr, nullptr, false, false};
+ OpenMPIRBuilder::AtomicOpValue R = {nullptr, nullptr, false, false};
AtomicOrdering AO = AtomicOrdering::Monotonic;
ConstantInt *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);
ConstantInt *D = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);
OMPAtomicCompareOp OpMax = OMPAtomicCompareOp::MAX;
OMPAtomicCompareOp OpEQ = OMPAtomicCompareOp::EQ;
- Builder.restoreIP(OMPBuilder.createAtomicCompare(Builder, XSigned, Expr,
- nullptr, AO, OpMax, true));
- Builder.restoreIP(OMPBuilder.createAtomicCompare(Builder, XUnsigned, Expr,
- nullptr, AO, OpMax, false));
- Builder.restoreIP(OMPBuilder.createAtomicCompare(Builder, XSigned, Expr, D,
- AO, OpEQ, true));
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, XSigned, V, R, Expr, nullptr, AO, OpMax, true, false, false));
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, XUnsigned, V, R, Expr, nullptr, AO, OpMax, false, false, false));
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, XSigned, V, R, Expr, D, AO, OpEQ, true, false, false));
BasicBlock *EntryBB = BB;
EXPECT_EQ(EntryBB->getParent()->size(), 1U);
@@ -3515,6 +3518,257 @@ TEST_F(OpenMPIRBuilderTest, OMPAtomicCompare) {
EXPECT_FALSE(verifyModule(*M, &errs()));
}
+TEST_F(OpenMPIRBuilderTest, OMPAtomicCompareCapture) {
+ OpenMPIRBuilder OMPBuilder(*M);
+ OMPBuilder.initialize();
+ F->setName("func");
+ IRBuilder<> Builder(BB);
+
+ OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL});
+
+ LLVMContext &Ctx = M->getContext();
+ IntegerType *Int32 = Type::getInt32Ty(Ctx);
+ AllocaInst *XVal = Builder.CreateAlloca(Int32);
+ XVal->setName("x");
+ AllocaInst *VVal = Builder.CreateAlloca(Int32);
+ VVal->setName("v");
+ AllocaInst *RVal = Builder.CreateAlloca(Int32);
+ RVal->setName("r");
+
+ StoreInst *Init =
+ Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal);
+
+ OpenMPIRBuilder::AtomicOpValue X = {XVal, Int32, true, false};
+ OpenMPIRBuilder::AtomicOpValue V = {VVal, Int32, false, false};
+ OpenMPIRBuilder::AtomicOpValue NoV = {nullptr, nullptr, false, false};
+ OpenMPIRBuilder::AtomicOpValue R = {RVal, Int32, false, false};
+ OpenMPIRBuilder::AtomicOpValue NoR = {nullptr, nullptr, false, false};
+
+ AtomicOrdering AO = AtomicOrdering::Monotonic;
+ ConstantInt *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);
+ ConstantInt *D = ConstantInt::get(Type::getInt32Ty(Ctx), 1U);
+ OMPAtomicCompareOp OpMax = OMPAtomicCompareOp::MAX;
+ OMPAtomicCompareOp OpEQ = OMPAtomicCompareOp::EQ;
+
+ // { cond-update-stmt v = x; }
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, X, V, NoR, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,
+ /* IsPostfixUpdate */ false,
+ /* IsFailOnly */ false));
+ // { v = x; cond-update-stmt }
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, X, V, NoR, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,
+ /* IsPostfixUpdate */ true,
+ /* IsFailOnly */ false));
+ // if(x == e) { x = d; } else { v = x; }
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, X, V, NoR, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,
+ /* IsPostfixUpdate */ false,
+ /* IsFailOnly */ true));
+ // { r = x == e; if(r) { x = d; } }
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, X, NoV, R, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,
+ /* IsPostfixUpdate */ false,
+ /* IsFailOnly */ false));
+ // { r = x == e; if(r) { x = d; } else { v = x; } }
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, X, V, R, Expr, D, AO, OpEQ, /* IsXBinopExpr */ true,
+ /* IsPostfixUpdate */ false,
+ /* IsFailOnly */ true));
+
+ // { v = x; cond-update-stmt }
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, X, V, NoR, Expr, nullptr, AO, OpMax, /* IsXBinopExpr */ true,
+ /* IsPostfixUpdate */ true,
+ /* IsFailOnly */ false));
+ // { cond-update-stmt v = x; }
+ Builder.restoreIP(OMPBuilder.createAtomicCompare(
+ Builder, X, V, NoR, Expr, nullptr, AO, OpMax, /* IsXBinopExpr */ false,
+ /* IsPostfixUpdate */ false,
+ /* IsFailOnly */ false));
+
+ BasicBlock *EntryBB = BB;
+ EXPECT_EQ(EntryBB->getParent()->size(), 5U);
+ BasicBlock *Cont1 = dyn_cast<BasicBlock>(EntryBB->getNextNode());
+ EXPECT_NE(Cont1, nullptr);
+ BasicBlock *Exit1 = dyn_cast<BasicBlock>(Cont1->getNextNode());
+ EXPECT_NE(Exit1, nullptr);
+ BasicBlock *Cont2 = dyn_cast<BasicBlock>(Exit1->getNextNode());
+ EXPECT_NE(Cont2, nullptr);
+ BasicBlock *Exit2 = dyn_cast<BasicBlock>(Cont2->getNextNode());
+ EXPECT_NE(Exit2, nullptr);
+
+ AtomicCmpXchgInst *CmpXchg1 =
+ dyn_cast<AtomicCmpXchgInst>(Init->getNextNode());
+ EXPECT_NE(CmpXchg1, nullptr);
+ EXPECT_EQ(CmpXchg1->getPointerOperand(), XVal);
+ EXPECT_EQ(CmpXchg1->getCompareOperand(), Expr);
+ EXPECT_EQ(CmpXchg1->getNewValOperand(), D);
+ ExtractValueInst *ExtVal1 =
+ dyn_cast<ExtractValueInst>(CmpXchg1->getNextNode());
+ EXPECT_NE(ExtVal1, nullptr);
+ EXPECT_EQ(ExtVal1->getAggregateOperand(), CmpXchg1);
+ EXPECT_EQ(ExtVal1->getIndices(), ArrayRef<unsigned int>(0U));
+ ExtractValueInst *ExtVal2 =
+ dyn_cast<ExtractValueInst>(ExtVal1->getNextNode());
+ EXPECT_NE(ExtVal2, nullptr);
+ EXPECT_EQ(ExtVal2->getAggregateOperand(), CmpXchg1);
+ EXPECT_EQ(ExtVal2->getIndices(), ArrayRef<unsigned int>(1U));
+ SelectInst *Sel1 = dyn_cast<SelectInst>(ExtVal2->getNextNode());
+ EXPECT_NE(Sel1, nullptr);
+ EXPECT_EQ(Sel1->getCondition(), ExtVal2);
+ EXPECT_EQ(Sel1->getTrueValue(), Expr);
+ EXPECT_EQ(Sel1->getFalseValue(), ExtVal1);
+ StoreInst *Store1 = dyn_cast<StoreInst>(Sel1->getNextNode());
+ EXPECT_NE(Store1, nullptr);
+ EXPECT_EQ(Store1->getPointerOperand(), VVal);
+ EXPECT_EQ(Store1->getValueOperand(), Sel1);
+
+ AtomicCmpXchgInst *CmpXchg2 =
+ dyn_cast<AtomicCmpXchgInst>(Store1->getNextNode());
+ EXPECT_NE(CmpXchg2, nullptr);
+ EXPECT_EQ(CmpXchg2->getPointerOperand(), XVal);
+ EXPECT_EQ(CmpXchg2->getCompareOperand(), Expr);
+ EXPECT_EQ(CmpXchg2->getNewValOperand(), D);
+ ExtractValueInst *ExtVal3 =
+ dyn_cast<ExtractValueInst>(CmpXchg2->getNextNode());
+ EXPECT_NE(ExtVal3, nullptr);
+ EXPECT_EQ(ExtVal3->getAggregateOperand(), CmpXchg2);
+ EXPECT_EQ(ExtVal3->getIndices(), ArrayRef<unsigned int>(0U));
+ StoreInst *Store2 = dyn_cast<StoreInst>(ExtVal3->getNextNode());
+ EXPECT_NE(Store2, nullptr);
+ EXPECT_EQ(Store2->getPointerOperand(), VVal);
+ EXPECT_EQ(Store2->getValueOperand(), ExtVal3);
+
+ AtomicCmpXchgInst *CmpXchg3 =
+ dyn_cast<AtomicCmpXchgInst>(Store2->getNextNode());
+ EXPECT_NE(CmpXchg3, nullptr);
+ EXPECT_EQ(CmpXchg3->getPointerOperand(), XVal);
+ EXPECT_EQ(CmpXchg3->getCompareOperand(), Expr);
+ EXPECT_EQ(CmpXchg3->getNewValOperand(), D);
+ ExtractValueInst *ExtVal4 =
+ dyn_cast<ExtractValueInst>(CmpXchg3->getNextNode());
+ EXPECT_NE(ExtVal4, nullptr);
+ EXPECT_EQ(ExtVal4->getAggregateOperand(), CmpXchg3);
+ EXPECT_EQ(ExtVal4->getIndices(), ArrayRef<unsigned int>(0U));
+ ExtractValueInst *ExtVal5 =
+ dyn_cast<ExtractValueInst>(ExtVal4->getNextNode());
+ EXPECT_NE(ExtVal5, nullptr);
+ EXPECT_EQ(ExtVal5->getAggregateOperand(), CmpXchg3);
+ EXPECT_EQ(ExtVal5->getIndices(), ArrayRef<unsigned int>(1U));
+ BranchInst *Br1 = dyn_cast<BranchInst>(ExtVal5->getNextNode());
+ EXPECT_NE(Br1, nullptr);
+ EXPECT_EQ(Br1->isConditional(), true);
+ EXPECT_EQ(Br1->getCondition(), ExtVal5);
+ EXPECT_EQ(Br1->getSuccessor(0), Exit1);
+ EXPECT_EQ(Br1->getSuccessor(1), Cont1);
+
+ StoreInst *Store3 = dyn_cast<StoreInst>(&Cont1->front());
+ EXPECT_NE(Store3, nullptr);
+ EXPECT_EQ(Store3->getPointerOperand(), VVal);
+ EXPECT_EQ(Store3->getValueOperand(), ExtVal4);
+ BranchInst *Br2 = dyn_cast<BranchInst>(Store3->getNextNode());
+ EXPECT_NE(Br2, nullptr);
+ EXPECT_EQ(Br2->isUnconditional(), true);
+ EXPECT_EQ(Br2->getSuccessor(0), Exit1);
+
+ AtomicCmpXchgInst *CmpXchg4 = dyn_cast<AtomicCmpXchgInst>(&Exit1->front());
+ EXPECT_NE(CmpXchg4, nullptr);
+ EXPECT_EQ(CmpXchg4->getPointerOperand(), XVal);
+ EXPECT_EQ(CmpXchg4->getCompareOperand(), Expr);
+ EXPECT_EQ(CmpXchg4->getNewValOperand(), D);
+ ExtractValueInst *ExtVal6 =
+ dyn_cast<ExtractValueInst>(CmpXchg4->getNextNode());
+ EXPECT_NE(ExtVal6, nullptr);
+ EXPECT_EQ(ExtVal6->getAggregateOperand(), CmpXchg4);
+ EXPECT_EQ(ExtVal6->getIndices(), ArrayRef<unsigned int>(1U));
+ ZExtInst *ZExt1 = dyn_cast<ZExtInst>(ExtVal6->getNextNode());
+ EXPECT_NE(ZExt1, nullptr);
+ EXPECT_EQ(ZExt1->getDestTy(), Int32);
+ StoreInst *Store4 = dyn_cast<StoreInst>(ZExt1->getNextNode());
+ EXPECT_NE(Store4, nullptr);
+ EXPECT_EQ(Store4->getPointerOperand(), RVal);
+ EXPECT_EQ(Store4->getValueOperand(), ZExt1);
+
+ AtomicCmpXchgInst *CmpXchg5 =
+ dyn_cast<AtomicCmpXchgInst>(Store4->getNextNode());
+ EXPECT_NE(CmpXchg5, nullptr);
+ EXPECT_EQ(CmpXchg5->getPointerOperand(), XVal);
+ EXPECT_EQ(CmpXchg5->getCompareOperand(), Expr);
+ EXPECT_EQ(CmpXchg5->getNewValOperand(), D);
+ ExtractValueInst *ExtVal7 =
+ dyn_cast<ExtractValueInst>(CmpXchg5->getNextNode());
+ EXPECT_NE(ExtVal7, nullptr);
+ EXPECT_EQ(ExtVal7->getAggregateOperand(), CmpXchg5);
+ EXPECT_EQ(ExtVal7->getIndices(), ArrayRef<unsigned int>(0U));
+ ExtractValueInst *ExtVal8 =
+ dyn_cast<ExtractValueInst>(ExtVal7->getNextNode());
+ EXPECT_NE(ExtVal8, nullptr);
+ EXPECT_EQ(ExtVal8->getAggregateOperand(), CmpXchg5);
+ EXPECT_EQ(ExtVal8->getIndices(), ArrayRef<unsigned int>(1U));
+ BranchInst *Br3 = dyn_cast<BranchInst>(ExtVal8->getNextNode());
+ EXPECT_NE(Br3, nullptr);
+ EXPECT_EQ(Br3->isConditional(), true);
+ EXPECT_EQ(Br3->getCondition(), ExtVal8);
+ EXPECT_EQ(Br3->getSuccessor(0), Exit2);
+ EXPECT_EQ(Br3->getSuccessor(1), Cont2);
+
+ StoreInst *Store5 = dyn_cast<StoreInst>(&Cont2->front());
+ EXPECT_NE(Store5, nullptr);
+ EXPECT_EQ(Store5->getPointerOperand(), VVal);
+ EXPECT_EQ(Store5->getValueOperand(), ExtVal7);
+ BranchInst *Br4 = dyn_cast<BranchInst>(Store5->getNextNode());
+ EXPECT_NE(Br4, nullptr);
+ EXPECT_EQ(Br4->isUnconditional(), true);
+ EXPECT_EQ(Br4->getSuccessor(0), Exit2);
+
+ ExtractValueInst *ExtVal9 = dyn_cast<ExtractValueInst>(&Exit2->front());
+ EXPECT_NE(ExtVal9, nullptr);
+ EXPECT_EQ(ExtVal9->getAggregateOperand(), CmpXchg5);
+ EXPECT_EQ(ExtVal9->getIndices(), ArrayRef<unsigned int>(1U));
+ ZExtInst *ZExt2 = dyn_cast<ZExtInst>(ExtVal9->getNextNode());
+ EXPECT_NE(ZExt2, nullptr);
+ EXPECT_EQ(ZExt2->getDestTy(), Int32);
+ StoreInst *Store6 = dyn_cast<StoreInst>(ZExt2->getNextNode());
+ EXPECT_NE(Store6, nullptr);
+ EXPECT_EQ(Store6->getPointerOperand(), RVal);
+ EXPECT_EQ(Store6->getValueOperand(), ZExt2);
+
+ AtomicRMWInst *ARWM1 = dyn_cast<AtomicRMWInst>(Store6->getNextNode());
+ EXPECT_NE(ARWM1, nullptr);
+ EXPECT_EQ(ARWM1->getPointerOperand(), XVal);
+ EXPECT_EQ(ARWM1->getValOperand(), Expr);
+ EXPECT_EQ(ARWM1->getOperation(), AtomicRMWInst::Min);
+ StoreInst *Store7 = dyn_cast<StoreInst>(ARWM1->getNextNode());
+ EXPECT_NE(Store7, nullptr);
+ EXPECT_EQ(Store7->getPointerOperand(), VVal);
+ EXPECT_EQ(Store7->getValueOperand(), ARWM1);
+
+ AtomicRMWInst *ARWM2 = dyn_cast<AtomicRMWInst>(Store7->getNextNode());
+ EXPECT_NE(ARWM2, nullptr);
+ EXPECT_EQ(ARWM2->getPointerOperand(), XVal);
+ EXPECT_EQ(ARWM2->getValOperand(), Expr);
+ EXPECT_EQ(ARWM2->getOperation(), AtomicRMWInst::Max);
+ CmpInst *Cmp1 = dyn_cast<CmpInst>(ARWM2->getNextNode());
+ EXPECT_NE(Cmp1, nullptr);
+ EXPECT_EQ(Cmp1->getPredicate(), CmpInst::ICMP_SGT);
+ EXPECT_EQ(Cmp1->getOperand(0), ARWM2);
+ EXPECT_EQ(Cmp1->getOperand(1), Expr);
+ SelectInst *Sel2 = dyn_cast<SelectInst>(Cmp1->getNextNode());
+ EXPECT_NE(Sel2, nullptr);
+ EXPECT_EQ(Sel2->getCondition(), Cmp1);
+ EXPECT_EQ(Sel2->getTrueValue(), Expr);
+ EXPECT_EQ(Sel2->getFalseValue(), ARWM2);
+ StoreInst *Store8 = dyn_cast<StoreInst>(Sel2->getNextNode());
+ EXPECT_NE(Store8, nullptr);
+ EXPECT_EQ(Store8->getPointerOperand(), VVal);
+ EXPECT_EQ(Store8->getValueOperand(), Sel2);
+
+ Builder.CreateRetVoid();
+ OMPBuilder.finalize();
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+}
+
/// Returns the single instruction of InstTy type in BB that uses the value V.
/// If there is more than one such instruction, returns null.
template <typename InstTy>
More information about the cfe-commits
mailing list