diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -1347,16 +1347,16 @@ enum AtomicCompareOp : unsigned { EQ, MIN, MAX }; /// Emit atomic compare for constructs: --- Only scalar data types - /// conditional-update-atomic: + /// cond-update-atomic: /// x = x ordop expr ? expr : x; /// x = expr ordop x ? expr : x; /// x = x == e ? d : x; - /// x = e == x ? d : x; (this one is not on the spec) + /// x = e == x ? d : x; (this one is not in the spec) /// cond-update-stmt: /// if (x ordop expr) { x = expr; } /// if (expr ordop x) { x = expr; } /// if (x == e) { x = d; } - /// if (e == x) { x = d; } (this one is not on th spec) + /// if (e == x) { x = d; } (this one is not in the spec) /// /// \param Loc The insert and source location description. /// \param AllocIP Instruction to create AllocaInst before. @@ -1368,15 +1368,14 @@ /// comparison. If forms that use 'ordop', it should be /// \p nullptr. /// \param AO Atomic ordering of the generated atomic instructions - /// \param UpdateOp Code generator for complex expressions that cannot be - /// expressed through atomicrmw instruction. + /// \param IsXBinopExpr True if the conditional statement is in the form where + /// x is on LHS. /// /// \return Insertion point after generated atomic capture IR. InsertPointTy createAtomicCompare(const LocationDescription &Loc, Instruction *AllocIP, AtomicOpValue &X, - AtomicOpValue &E, Value *D, - AtomicOrdering AO, AtomicCompareOp Op, - AtomicUpdateCallbackTy &UpdateOp); + Value *E, Value *D, AtomicOrdering AO, + AtomicCompareOp Op, bool IsXBinopExpr); /// 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 --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -3472,15 +3472,14 @@ return Builder.saveIP(); } -OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicCompare( - const LocationDescription &Loc, Instruction *AllocIP, AtomicOpValue &X, - AtomicOpValue &E, Value *D, AtomicOrdering AO, AtomicCompareOp Op, - AtomicUpdateCallbackTy &UpdateOp) { +OpenMPIRBuilder::InsertPointTy +OpenMPIRBuilder::createAtomicCompare(const LocationDescription &Loc, + Instruction *AllocIP, AtomicOpValue &X, + Value *E, Value *D, AtomicOrdering AO, + AtomicCompareOp Op, bool IsXBinopExpr) { if (!updateToLocation(Loc)) return Loc.IP; - Type *XElemTy = X.Var->getType()->getPointerElementType(); - LLVM_DEBUG({ Type *XTy = X.Var->getType(); assert(XTy->isPointerTy() && @@ -3492,23 +3491,46 @@ }); if (Op == AtomicCompareOp::EQ) { - LLVM_DEBUG({ - assert(D && "D should be valid for forms use an equality comparison"); - }); - unsigned Addrspace = cast(X.Var->getType())->getAddressSpace(); IntegerType *IntCastTy = - IntegerType::get(M.getContext(), XElemTy->getScalarSizeInBits()); + IntegerType::get(M.getContext(), X.ElemTy->getScalarSizeInBits()); Value *XAddr = - XElemTy->isIntegerTy() + X.ElemTy->isIntegerTy() ? X.Var : Builder.CreateBitCast(X.Var, IntCastTy->getPointerTo(Addrspace)); - AtomicOrdering Failure = - llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO); - AtomicCmpXchgInst *Result = Builder.CreateAtomicCmpXchg( - XAddr, E.Var, D, llvm::MaybeAlign(), AO, Failure); + AtomicOrdering Failure = AtomicCmpXchgInst::getStrongestFailureOrdering(AO); + // We don't need the result for now. + (void)Builder.CreateAtomicCmpXchg(XAddr, E, D, llvm::MaybeAlign(), AO, + Failure); } else { + assert(Op == AtomicCompareOp::MAX || Op == AtomicCompareOp::MIN); + assert(X.ElemTy->isIntegerTy() && + "max and min operators only support integer type"); + // Reverse the ordop as the OpenMP forms are different from LLVM forms. + // Let's take max as example. + // OpenMP form: + // x = x > expr ? expr : x; + // LLVM form: + // *ptr = *ptr > val ? *ptr : val; + // We need to transform to LLVM form. + // x = x <= expr ? x : expr; + AtomicRMWInst::BinOp NewOp; + if (IsXBinopExpr) { + if (Op == AtomicCompareOp::MAX) { + // TODO: Check if signed or unsigned. + NewOp = AtomicRMWInst::Min; + } else { + // TODO: Check if signed or unsigned. + NewOp = AtomicRMWInst::Max; + } + } else { + // TODO: Check if signed or unsigned. + NewOp = + Op == AtomicCompareOp::MAX ? AtomicRMWInst::Max : AtomicRMWInst::Min; + } + // We dont' need the result for now. + (void)Builder.CreateAtomicRMW(NewOp, X.Var, E, MaybeAlign(), AO); } checkAndEmitFlushAfterAtomic(Loc, AO, AtomicKind::Compare);