[cfe-commits] [PATCH] atomic operation builtins, part 1
Eli Friedman
eli.friedman at gmail.com
Thu Oct 6 18:36:10 PDT 2011
Atomic ops; similar to the patch I submitted earlier, but this version
adds the restriction that the first operand to the __atomic_*
operations must be an _Atomic(T)*. I'm sending this to double-check
that I haven't missed any serious issues.
After this is committed, I'll put together a patch for
__atomic_is_lock_free, including the necessary machinery to come up
with the right answers.
-Eli
-------------- next part --------------
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td (revision 141335)
+++ include/clang/Basic/StmtNodes.td (working copy)
@@ -78,6 +78,9 @@
def VAArgExpr : DStmt<Expr>;
def GenericSelectionExpr : DStmt<Expr>;
+// Atomic expressions
+def AtomicExpr : DStmt<Expr>;
+
// GNU Extensions.
def AddrLabelExpr : DStmt<Expr>;
def StmtExpr : DStmt<Expr>;
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def (revision 141335)
+++ include/clang/Basic/Builtins.def (working copy)
@@ -585,8 +585,19 @@
BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "n")
BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "n")
+BUILTIN(__atomic_load, "v.", "t")
+BUILTIN(__atomic_store, "v.", "t")
+BUILTIN(__atomic_exchange, "v.", "t")
+BUILTIN(__atomic_compare_exchange_strong, "v.", "t")
+BUILTIN(__atomic_compare_exchange_weak, "v.", "t")
+BUILTIN(__atomic_fetch_add, "v.", "t")
+BUILTIN(__atomic_fetch_sub, "v.", "t")
+BUILTIN(__atomic_fetch_and, "v.", "t")
+BUILTIN(__atomic_fetch_or, "v.", "t")
+BUILTIN(__atomic_fetch_xor, "v.", "t")
+BUILTIN(__atomic_thread_fence, "vi", "t")
+BUILTIN(__atomic_signal_fence, "vi", "t")
-
// Non-overloaded atomic builtins.
BUILTIN(__sync_synchronize, "v.", "n")
// GCC does not support these, they are a Clang extension.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td (revision 141335)
+++ include/clang/Basic/DiagnosticSemaKinds.td (working copy)
@@ -4000,6 +4000,15 @@
def err_atomic_builtin_pointer_size : Error<
"first argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte "
"type (%0 invalid)">;
+def err_atomic_builtin_needs_atomic : Error<
+ "first argument to atomic builtin must be a pointer to atomic "
+ " type (%0 invalid)">;
+def err_atomic_builtin_needs_atomic_int_or_ptr : Error<
+ "first argument to atomic builtin must be a pointer to atomic "
+ " integer or pointer (%0 invalid)">;
+def err_atomic_builtin_logical_needs_atomic_int : Error<
+ "first argument to logical atomic builtin must be a pointer to atomic "
+ " integer (%0 invalid)">;
def err_deleted_function_use : Error<"attempt to use a deleted function">;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h (revision 141335)
+++ include/clang/Sema/Sema.h (working copy)
@@ -6095,6 +6095,8 @@
bool SemaBuiltinObjectSize(CallExpr *TheCall);
bool SemaBuiltinLongjmp(CallExpr *TheCall);
ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult);
+ ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult,
+ AtomicExpr::AtomicOp Op);
bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
llvm::APSInt &Result);
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h (revision 141335)
+++ include/clang/AST/RecursiveASTVisitor.h (working copy)
@@ -1992,6 +1992,7 @@
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
+DEF_TRAVERSE_STMT(AtomicExpr, { })
// These literals (all of them) do not need any action.
DEF_TRAVERSE_STMT(IntegerLiteral, { })
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h (revision 141335)
+++ include/clang/AST/Expr.h (working copy)
@@ -4157,6 +4157,128 @@
// Iterators
child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
};
+
+/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
+/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the
+/// similarly-named C++0x instructions. All of these instructions take one
+/// primary pointer and at least one memory order.
+class AtomicExpr : public Expr {
+public:
+ enum AtomicOp { Load, Store, CmpXchgStrong, CmpXchgWeak, Xchg,
+ Add, Sub, And, Or, Xor };
+private:
+ enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, END_EXPR };
+ Stmt* SubExprs[END_EXPR];
+ unsigned NumSubExprs;
+ SourceLocation BuiltinLoc, RParenLoc;
+ AtomicOp Op;
+
+public:
+ // Constructor for Load
+ AtomicExpr(SourceLocation BLoc, Expr *ptr, Expr *order, QualType t,
+ AtomicOp op, SourceLocation RP,
+ bool TypeDependent, bool ValueDependent)
+ : Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary,
+ TypeDependent, ValueDependent,
+ ptr->isInstantiationDependent(),
+ ptr->containsUnexpandedParameterPack()),
+ BuiltinLoc(BLoc), RParenLoc(RP), Op(op) {
+ SubExprs[PTR] = ptr;
+ SubExprs[ORDER] = order;
+ NumSubExprs = 2;
+ }
+
+ // Constructor for Store, Xchg, Add, Sub, And, Or, Xor
+ AtomicExpr(SourceLocation BLoc, Expr *ptr, Expr *val, Expr *order,
+ QualType t, AtomicOp op, SourceLocation RP,
+ bool TypeDependent, bool ValueDependent)
+ : Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary,
+ TypeDependent, ValueDependent,
+ (ptr->isInstantiationDependent() ||
+ val->isInstantiationDependent()),
+ (ptr->containsUnexpandedParameterPack() ||
+ val->containsUnexpandedParameterPack())),
+ BuiltinLoc(BLoc), RParenLoc(RP), Op(op) {
+ SubExprs[PTR] = ptr;
+ SubExprs[ORDER] = order;
+ SubExprs[VAL1] = val;
+ NumSubExprs = 3;
+ }
+
+ // Constructor for CmpXchgStrong, CmpXchgWeak
+ AtomicExpr(SourceLocation BLoc, Expr *ptr, Expr *val1, Expr *val2,
+ Expr *order, Expr *order_fail, QualType t, AtomicOp op,
+ SourceLocation RP, bool TypeDependent, bool ValueDependent)
+ : Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary,
+ TypeDependent, ValueDependent,
+ (ptr->isInstantiationDependent() ||
+ val1->isInstantiationDependent() ||
+ val2->isInstantiationDependent()),
+ (ptr->containsUnexpandedParameterPack() ||
+ val1->containsUnexpandedParameterPack() ||
+ val2->containsUnexpandedParameterPack())),
+ BuiltinLoc(BLoc), RParenLoc(RP), Op(op) {
+ SubExprs[PTR] = ptr;
+ SubExprs[VAL1] = val1;
+ SubExprs[ORDER] = order;
+ SubExprs[VAL2] = val2;
+ SubExprs[ORDER_FAIL] = order_fail;
+ NumSubExprs = 5;
+ }
+
+ /// \brief Build an empty __builtin_choose_expr.
+ explicit AtomicExpr(EmptyShell Empty) : Expr(AtomicExprClass, Empty) { }
+
+ Expr *getPtr() const { return cast<Expr>(SubExprs[PTR]); }
+ void setPtr(Expr *E) { SubExprs[PTR] = E; }
+ Expr *getOrder() const { return cast<Expr>(SubExprs[ORDER]); }
+ void setOrder(Expr *E) { SubExprs[ORDER] = E; }
+ Expr *getVal1() const { return cast<Expr>(SubExprs[VAL1]); }
+ void setVal1(Expr *E) { SubExprs[VAL1] = E; }
+ Expr *getOrderFail() const { return cast<Expr>(SubExprs[ORDER_FAIL]); }
+ void setOrderFail(Expr *E) { SubExprs[ORDER_FAIL] = E; }
+ Expr *getVal2() const { return cast<Expr>(SubExprs[VAL2]); }
+ void setVal2(Expr *E) { SubExprs[VAL2] = E; }
+
+ AtomicOp getOp() const { return Op; }
+ void setOp(AtomicOp op) { Op = op; }
+ unsigned getNumSubExprs() { return NumSubExprs; }
+ void setNumSubExprs(unsigned num) { NumSubExprs = num; }
+
+ int getOrderVal(ASTContext &Ctx) const {
+ return getOrder()->EvaluateAsInt(Ctx).getZExtValue();
+ }
+ int getOrderFailVal(ASTContext &Ctx) const {
+ return getOrderFail()->EvaluateAsInt(Ctx).getZExtValue();
+ }
+ bool isVolatile() const {
+ return getPtr()->getType()->getPointeeType().isVolatileQualified();
+ }
+
+ bool isCmpXChg() const {
+ return getOp() == AtomicExpr::CmpXchgStrong ||
+ getOp() == AtomicExpr::CmpXchgWeak;
+ }
+
+ SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
+ void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
+
+ SourceLocation getRParenLoc() const { return RParenLoc; }
+ void setRParenLoc(SourceLocation L) { RParenLoc = L; }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(BuiltinLoc, RParenLoc);
+ }
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == AtomicExprClass;
+ }
+ static bool classof(const AtomicExpr *) { return true; }
+
+ // Iterators
+ child_range children() {
+ return child_range(SubExprs, SubExprs+NumSubExprs);
+ }
+};
} // end namespace clang
#endif
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h (revision 141335)
+++ include/clang/Serialization/ASTBitCodes.h (working copy)
@@ -973,7 +973,9 @@
EXPR_BLOCK_DECL_REF,
/// \brief A GenericSelectionExpr record.
EXPR_GENERIC_SELECTION,
-
+ /// \brief An AtomicExpr record.
+ EXPR_ATOMIC,
+
// Objective-C
/// \brief An ObjCStringLiteral record.
Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp (revision 141335)
+++ tools/libclang/CXCursor.cpp (working copy)
@@ -201,6 +201,7 @@
case Stmt::ArrayTypeTraitExprClass:
case Stmt::AsTypeExprClass:
+ case Stmt::AtomicExprClass:
case Stmt::BinaryConditionalOperatorClass:
case Stmt::BinaryTypeTraitExprClass:
case Stmt::CXXBindTemporaryExprClass:
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h (revision 141335)
+++ lib/Sema/TreeTransform.h (working copy)
@@ -8085,6 +8085,13 @@
TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) {
llvm_unreachable("Cannot transform asType expressions yet");
}
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
+ assert(false && "Cannot transform atomic expressions yet");
+ return SemaRef.Owned(E);
+}
//===----------------------------------------------------------------------===//
// Type reconstruction
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp (revision 141335)
+++ lib/Sema/SemaChecking.cpp (working copy)
@@ -15,6 +15,7 @@
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
@@ -197,6 +198,28 @@
case Builtin::BI__sync_lock_release:
case Builtin::BI__sync_swap:
return SemaBuiltinAtomicOverloaded(move(TheCallResult));
+ case Builtin::BI__atomic_load:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Load);
+ case Builtin::BI__atomic_store:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Store);
+ case Builtin::BI__atomic_exchange:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xchg);
+ case Builtin::BI__atomic_compare_exchange_strong:
+ return SemaAtomicOpsOverloaded(move(TheCallResult),
+ AtomicExpr::CmpXchgStrong);
+ case Builtin::BI__atomic_compare_exchange_weak:
+ return SemaAtomicOpsOverloaded(move(TheCallResult),
+ AtomicExpr::CmpXchgWeak);
+ case Builtin::BI__atomic_fetch_add:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Add);
+ case Builtin::BI__atomic_fetch_sub:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Sub);
+ case Builtin::BI__atomic_fetch_and:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::And);
+ case Builtin::BI__atomic_fetch_or:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Or);
+ case Builtin::BI__atomic_fetch_xor:
+ return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::Xor);
case Builtin::BI__builtin_annotation:
if (CheckBuiltinAnnotationString(*this, TheCall->getArg(1)))
return ExprError();
@@ -414,6 +437,141 @@
return false;
}
+ExprResult
+Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) {
+ CallExpr *TheCall = (CallExpr *)TheCallResult.get();
+ DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ Expr *Ptr, *Order, *Val1, *Val2, *OrderFail;
+
+ unsigned NumVals = 1;
+ unsigned NumOrders = 1;
+ if (Op == AtomicExpr::Load) {
+ NumVals = 0;
+ } else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong) {
+ NumVals = 2;
+ NumOrders = 2;
+ }
+
+ if (TheCall->getNumArgs() < NumVals+NumOrders+1) {
+ Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
+ return ExprError();
+ } else if (TheCall->getNumArgs() > NumVals+NumOrders+1) {
+ Diag(TheCall->getArg(2)->getLocStart(),
+ diag::err_typecheck_call_too_many_args)
+ << 0 << NumVals+NumOrders+1 << TheCall->getNumArgs()
+ << TheCall->getCallee()->getSourceRange();
+ return ExprError();
+ }
+
+ // Inspect the first argument of the atomic builtin. This should always be
+ // a pointer type, whose element is an integral scalar or pointer type.
+ Ptr = TheCall->getArg(0);
+ Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get();
+ const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
+ if (!pointerType) {
+ Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ QualType AtomTy = pointerType->getPointeeType();
+ if (!AtomTy->isAtomicType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_builtin_needs_atomic)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+ QualType ValType = cast<AtomicType>(AtomTy)->getValueType();
+
+ if ((Op == AtomicExpr::Add || Op == AtomicExpr::Sub) &&
+ !ValType->isIntegerType() && !ValType->isAnyPointerType() &&
+ !ValType->isBlockPointerType()) {
+ Diag(DRE->getLocStart(), diag::err_atomic_builtin_needs_atomic_int_or_ptr)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ if (!ValType->isIntegerType() &&
+ (Op == AtomicExpr::And || Op == AtomicExpr::Or || Op == AtomicExpr::Xor)){
+ Diag(DRE->getLocStart(), diag::err_atomic_builtin_logical_needs_atomic_int)
+ << Ptr->getType() << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ switch (ValType.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ // okay
+ break;
+
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Autoreleasing:
+ Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership)
+ << ValType << Ptr->getSourceRange();
+ return ExprError();
+ }
+
+ QualType ResultType = ValType;
+ if (Op == AtomicExpr::Store)
+ ResultType = Context.VoidTy;
+ else if (Op == AtomicExpr::CmpXchgWeak || Op == AtomicExpr::CmpXchgStrong)
+ ResultType = Context.BoolTy;
+
+ // The first argument --- the pointer --- has a fixed type; we
+ // deduce the types of the rest of the arguments accordingly. Walk
+ // the remaining arguments, converting them to the deduced value type.
+ for (unsigned i = 0; i != NumVals+NumOrders; ++i) {
+ ExprResult Arg = TheCall->getArg(i+1);
+ QualType Ty;
+ if (i < NumVals) {
+ if (i == 0 && (Op == AtomicExpr::CmpXchgWeak ||
+ Op == AtomicExpr::CmpXchgStrong))
+ Ty = Context.getPointerType(ValType.getUnqualifiedType());
+ else if (!ValType->isIntegerType() &&
+ (Op == AtomicExpr::Add || Op == AtomicExpr::Sub))
+ Ty = Context.getPointerDiffType();
+ else
+ Ty = ValType;
+ } else {
+ Ty = Context.IntTy;
+ }
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(Context, Ty, false);
+ Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
+ if (Arg.isInvalid())
+ return true;
+ TheCall->setArg(i+1, Arg.get());
+ }
+
+ if (Op == AtomicExpr::Load) {
+ Order = TheCall->getArg(1);
+ return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
+ Ptr, Order, ResultType, Op,
+ TheCall->getRParenLoc(), false,
+ false));
+ } else if (Op != AtomicExpr::CmpXchgWeak && Op != AtomicExpr::CmpXchgStrong) {
+ Val1 = TheCall->getArg(1);
+ Order = TheCall->getArg(2);
+ return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
+ Ptr, Val1, Order, ResultType, Op,
+ TheCall->getRParenLoc(), false,
+ false));
+ } else {
+ Val1 = TheCall->getArg(1);
+ Val2 = TheCall->getArg(2);
+ Order = TheCall->getArg(3);
+ OrderFail = TheCall->getArg(4);
+ return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(),
+ Ptr, Val1, Val2, Order, OrderFail,
+ ResultType, Op,
+ TheCall->getRParenLoc(), false,
+ false));
+ }
+}
+
+
/// checkBuiltinArgument - Given a call to a builtin function, perform
/// normal type-checking on the given argument, updating the call in
/// place. This is useful when a builtin function requires custom
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp (revision 141335)
+++ lib/AST/ExprConstant.cpp (working copy)
@@ -2847,6 +2847,7 @@
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::MaterializeTemporaryExprClass:
+ case Expr::AtomicExprClass:
return ICEDiag(2, E->getLocStart());
case Expr::InitListExprClass:
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp (revision 141335)
+++ lib/AST/ItaniumMangle.cpp (working copy)
@@ -2255,6 +2255,7 @@
case Expr::CXXNoexceptExprClass:
case Expr::CUDAKernelCallExprClass:
case Expr::AsTypeExprClass:
+ case Expr::AtomicExprClass:
{
// As bad as this diagnostic is, it's better than crashing.
DiagnosticsEngine &Diags = Context.getDiags();
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp (revision 141335)
+++ lib/AST/StmtPrinter.cpp (working copy)
@@ -1011,6 +1011,59 @@
OS << ")";
}
+void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
+ const char *Name;
+ switch (Node->getOp()) {
+ case AtomicExpr::Load:
+ Name = "__atomic_load(";
+ break;
+ case AtomicExpr::Store:
+ Name = "__atomic_store(";
+ break;
+ case AtomicExpr::CmpXchgStrong:
+ Name = "__atomic_compare_exchange_strong(";
+ break;
+ case AtomicExpr::CmpXchgWeak:
+ Name = "__atomic_compare_exchange_weak(";
+ break;
+ case AtomicExpr::Xchg:
+ Name = "__atomic_exchange(";
+ break;
+ case AtomicExpr::Add:
+ Name = "__atomic_fetch_add(";
+ break;
+ case AtomicExpr::Sub:
+ Name = "__atomic_fetch_sub(";
+ break;
+ case AtomicExpr::And:
+ Name = "__atomic_fetch_and(";
+ break;
+ case AtomicExpr::Or:
+ Name = "__atomic_fetch_or(";
+ break;
+ case AtomicExpr::Xor:
+ Name = "__atomic_fetch_xor(";
+ break;
+ }
+ OS << Name;
+ PrintExpr(Node->getPtr());
+ OS << ", ";
+ if (Node->getOp() != AtomicExpr::Load) {
+ PrintExpr(Node->getVal1());
+ OS << ", ";
+ }
+ if (Node->isCmpXChg()) {
+ PrintExpr(Node->getVal2());
+ OS << ", ";
+ }
+ PrintExpr(Node->getOrder());
+ if (Node->isCmpXChg()) {
+ OS << ", ";
+ PrintExpr(Node->getOrderFail());
+ }
+ OS << ")";
+}
+
// C++
void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) {
const char *OpStrings[NUM_OVERLOADED_OPERATORS] = {
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp (revision 141335)
+++ lib/AST/StmtProfile.cpp (working copy)
@@ -468,6 +468,10 @@
}
}
+void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {
+ VisitExpr(S);
+}
+
static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp (revision 141335)
+++ lib/AST/Expr.cpp (working copy)
@@ -1537,6 +1537,7 @@
}
case CompoundAssignOperatorClass:
case VAArgExprClass:
+ case AtomicExprClass:
return false;
case ConditionalOperatorClass: {
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp (revision 141335)
+++ lib/AST/ExprClassification.cpp (working copy)
@@ -162,6 +162,7 @@
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
+ case Expr::AtomicExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp (revision 141335)
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp (working copy)
@@ -565,6 +565,7 @@
case Stmt::CUDAKernelCallExprClass:
case Stmt::OpaqueValueExprClass:
case Stmt::AsTypeExprClass:
+ case Stmt::AtomicExprClass:
// Fall through.
// Cases we intentionally don't evaluate, since they don't need
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp (revision 141335)
+++ lib/CodeGen/CGExprScalar.cpp (working copy)
@@ -513,6 +513,7 @@
return CGF.EmitObjCStringLiteral(E);
}
Value *VisitAsTypeExpr(AsTypeExpr *CE);
+ Value *VisitAtomicExpr(AtomicExpr *AE);
};
} // end anonymous namespace.
@@ -2637,6 +2638,10 @@
return Builder.CreateBitCast(Src, DstTy, "astype");
}
+Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) {
+ return CGF.EmitAtomicExpr(E).getScalarVal();
+}
+
//===----------------------------------------------------------------------===//
// Entry Point into this File
//===----------------------------------------------------------------------===//
Index: lib/CodeGen/CGExprComplex.cpp
===================================================================
--- lib/CodeGen/CGExprComplex.cpp (revision 141335)
+++ lib/CodeGen/CGExprComplex.cpp (working copy)
@@ -266,6 +266,10 @@
ComplexPairTy VisitInitListExpr(InitListExpr *E);
ComplexPairTy VisitVAArgExpr(VAArgExpr *E);
+
+ ComplexPairTy VisitAtomicExpr(AtomicExpr *E) {
+ return CGF.EmitAtomicExpr(E).getComplexVal();
+ }
};
} // end anonymous namespace.
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp (revision 141335)
+++ lib/CodeGen/CGExpr.cpp (working copy)
@@ -2478,3 +2478,266 @@
return MakeAddrLValue(AddV, MPT->getPointeeType());
}
+
+static void
+EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
+ llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2,
+ uint64_t Size, unsigned Align, llvm::AtomicOrdering Order) {
+ if (E->isCmpXChg()) {
+ // Note that cmpxchg only supports specifying one ordering and
+ // doesn't support weak cmpxchg, at least at the moment.
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::LoadInst *LoadVal2 = CGF.Builder.CreateLoad(Val2);
+ LoadVal2->setAlignment(Align);
+ llvm::AtomicCmpXchgInst *CXI =
+ CGF.Builder.CreateAtomicCmpXchg(Ptr, LoadVal1, LoadVal2, Order);
+ CXI->setVolatile(E->isVolatile());
+ llvm::StoreInst *StoreVal1 = CGF.Builder.CreateStore(CXI, Val1);
+ StoreVal1->setAlignment(Align);
+ llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(CXI, LoadVal1);
+ CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
+ return;
+ }
+
+ if (E->getOp() == AtomicExpr::Load) {
+ llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
+ Load->setAtomic(Order);
+ Load->setAlignment(Size);
+ Load->setVolatile(E->isVolatile());
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Load, Dest);
+ StoreDest->setAlignment(Align);
+ return;
+ }
+
+ if (E->getOp() == AtomicExpr::Store) {
+ assert(!Dest && "Store does not return a value");
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
+ Store->setAtomic(Order);
+ Store->setAlignment(Size);
+ Store->setVolatile(E->isVolatile());
+ return;
+ }
+
+ llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
+ switch (E->getOp()) {
+ case AtomicExpr::CmpXchgWeak:
+ case AtomicExpr::CmpXchgStrong:
+ case AtomicExpr::Store:
+ case AtomicExpr::Load: assert(0 && "Already handled!");
+ case AtomicExpr::Add: Op = llvm::AtomicRMWInst::Add; break;
+ case AtomicExpr::Sub: Op = llvm::AtomicRMWInst::Sub; break;
+ case AtomicExpr::And: Op = llvm::AtomicRMWInst::And; break;
+ case AtomicExpr::Or: Op = llvm::AtomicRMWInst::Or; break;
+ case AtomicExpr::Xor: Op = llvm::AtomicRMWInst::Xor; break;
+ case AtomicExpr::Xchg: Op = llvm::AtomicRMWInst::Xchg; break;
+ }
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::AtomicRMWInst *RMWI =
+ CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order);
+ RMWI->setVolatile(E->isVolatile());
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(RMWI, Dest);
+ StoreDest->setAlignment(Align);
+}
+
+static llvm::Value *
+EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
+ llvm::Value *DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
+ CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
+ /*Init*/ true);
+ return DeclPtr;
+}
+
+static RValue ConvertTempToRValue(CodeGenFunction &CGF, QualType Ty,
+ llvm::Value *Dest) {
+ if (Ty->isAnyComplexType())
+ return RValue::getComplex(CGF.LoadComplexFromAddr(Dest, false));
+ if (CGF.hasAggregateLLVMType(Ty))
+ return RValue::getAggregate(Dest);
+ return RValue::get(CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(Dest, Ty)));
+}
+
+RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
+ QualType PointeeTy = E->getPtr()->getType()->getPointeeType();
+ CharUnits sizeChars = getContext().getTypeSizeInChars(PointeeTy);
+ uint64_t Size = sizeChars.getQuantity();
+ CharUnits alignChars = getContext().getTypeSizeInChars(PointeeTy);
+ unsigned Align = alignChars.getQuantity();
+ // FIXME: Bound on Size should not be hardcoded.
+ bool UseLibcall = (!llvm::isPowerOf2_64(Size) || Size > 8);
+
+ llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
+ Ptr = EmitScalarExpr(E->getPtr());
+ Order = EmitScalarExpr(E->getOrder());
+ if (E->isCmpXChg()) {
+ Val1 = EmitScalarExpr(E->getVal1());
+ Val2 = EmitValToTemp(*this, E->getVal2());
+ OrderFail = EmitScalarExpr(E->getOrderFail());
+ (void)OrderFail; // OrderFail is unused at the moment
+ } else if (E->getOp() != AtomicExpr::Load) {
+ Val1 = EmitValToTemp(*this, E->getVal1());
+ }
+
+ llvm::Type *PointeeLLVMTy =
+ cast<llvm::PointerType>(Ptr->getType())->getElementType();
+
+ llvm::Type *InstrReturnTy = PointeeLLVMTy;
+ if (E->isCmpXChg())
+ InstrReturnTy = Builder.getInt1Ty();
+ else if (E->getOp() == AtomicExpr::Store)
+ InstrReturnTy = 0;
+
+ if (InstrReturnTy && !Dest)
+ Dest = CreateMemTemp(E->getType(), ".atomicdst");
+
+ if (UseLibcall) {
+ // FIXME: Finalize what the libcalls are actually supposed to look like.
+ return EmitUnsupportedRValue(E, "atomic library call");
+ }
+#if 0
+ if (UseLibcall) {
+ const char* LibCallName;
+ switch (E->getOp()) {
+ case AtomicExpr::CmpXchgWeak:
+ LibCallName = "__atomic_compare_exchange_generic"; break;
+ case AtomicExpr::CmpXchgStrong:
+ LibCallName = "__atomic_compare_exchange_generic"; break;
+ case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break;
+ case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break;
+ case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break;
+ case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break;
+ case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break;
+ case AtomicExpr::Xchg: LibCallName = "__atomic_exchange_generic"; break;
+ case AtomicExpr::Store: LibCallName = "__atomic_store_generic"; break;
+ case AtomicExpr::Load: LibCallName = "__atomic_load_generic"; break;
+ }
+ llvm::SmallVector<QualType, 4> Params;
+ CallArgList Args;
+ QualType RetTy = getContext().VoidTy;
+ if (E->getOp() != AtomicExpr::Store && !E->isCmpXChg())
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
+ getContext().VoidPtrTy);
+ if (E->getOp() != AtomicExpr::Load)
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ if (E->isCmpXChg()) {
+ Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
+ getContext().VoidPtrTy);
+ RetTy = getContext().IntTy;
+ }
+ Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
+ getContext().getSizeType());
+ const CGFunctionInfo &FuncInfo =
+ CGM.getTypes().getFunctionInfo(RetTy, Args, FunctionType::ExtInfo());
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo, false);
+ llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
+ RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
+ if (E->isCmpXChg())
+ return Res;
+ if (E->getOp() == AtomicExpr::Store)
+ return RValue::get(0);
+ return ConvertTempToRValue(*this, E->getType(), Dest);
+ }
+#endif
+ llvm::Type *IPtrTy =
+ llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
+ llvm::Value *OrigDest = Dest;
+ Ptr = Builder.CreateBitCast(Ptr, IPtrTy);
+ if (Val1) Val1 = Builder.CreateBitCast(Val1, IPtrTy);
+ if (Val2) Val2 = Builder.CreateBitCast(Val2, IPtrTy);
+ if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy);
+
+ if (isa<llvm::ConstantInt>(Order)) {
+ int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
+ switch (ord) {
+ case 0: // memory_order_relaxed
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Monotonic);
+ break;
+ case 1: // memory_order_consume
+ case 2: // memory_order_acquire
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Acquire);
+ break;
+ case 3: // memory_order_release
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Release);
+ break;
+ case 4: // memory_order_acq_rel
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::AcquireRelease);
+ break;
+ case 5: // memory_order_seq_cst
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::SequentiallyConsistent);
+ break;
+ default: // invalid order
+ llvm::UndefValue::get(InstrReturnTy);
+ }
+ if (E->getOp() == AtomicExpr::Store)
+ RValue::get(0);
+ return ConvertTempToRValue(*this, E->getType(), OrigDest);
+ }
+
+ // Long case, when Order isn't obviously constant.
+
+ // Create all the relevant BB's
+ llvm::BasicBlock *MonotonicBB, *AcquireBB, *ReleaseBB, *AcqRelBB, *SeqCstBB;
+ MonotonicBB = createBasicBlock("monotonic", CurFn);
+ if (E->getOp() != AtomicExpr::Store)
+ AcquireBB = createBasicBlock("acquire", CurFn);
+ if (E->getOp() != AtomicExpr::Load)
+ ReleaseBB = createBasicBlock("release", CurFn);
+ if (E->getOp() != AtomicExpr::Load && E->getOp() != AtomicExpr::Store)
+ AcqRelBB = createBasicBlock("acqrel", CurFn);
+ SeqCstBB = createBasicBlock("seqcst", CurFn);
+ llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
+
+ // Create the switch and PHI for the split
+ Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
+ llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
+
+ // Emit all the different atomics
+ Builder.SetInsertPoint(MonotonicBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Monotonic);
+ Builder.CreateBr(ContBB);
+ if (E->getOp() != AtomicExpr::Store) {
+ Builder.SetInsertPoint(AcquireBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Acquire);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(1), AcquireBB);
+ SI->addCase(Builder.getInt32(2), AcquireBB);
+ }
+ if (E->getOp() != AtomicExpr::Load) {
+ Builder.SetInsertPoint(ReleaseBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Release);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(3), ReleaseBB);
+ }
+ if (E->getOp() != AtomicExpr::Load && E->getOp() != AtomicExpr::Store) {
+ Builder.SetInsertPoint(AcqRelBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::AcquireRelease);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(4), AcqRelBB);
+ }
+ Builder.SetInsertPoint(SeqCstBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::SequentiallyConsistent);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(5), SeqCstBB);
+
+ // Cleanup and return
+ Builder.SetInsertPoint(ContBB);
+ if (E->getOp() == AtomicExpr::Store)
+ RValue::get(0);
+ return ConvertTempToRValue(*this, E->getType(), OrigDest);
+}
Index: lib/CodeGen/CGExprAgg.cpp
===================================================================
--- lib/CodeGen/CGExprAgg.cpp (revision 141335)
+++ lib/CodeGen/CGExprAgg.cpp (working copy)
@@ -154,6 +154,9 @@
void EmitNullInitializationToLValue(LValue Address);
// case Expr::ChooseExprClass:
void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); }
+ void VisitAtomicExpr(AtomicExpr *E) {
+ CGF.EmitAtomicExpr(E, EnsureSlot(E->getType()).getAddr());
+ }
};
} // end anonymous namespace.
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h (revision 141335)
+++ lib/CodeGen/CodeGenFunction.h (working copy)
@@ -2283,6 +2283,8 @@
void EmitCXXThrowExpr(const CXXThrowExpr *E);
+ RValue EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest = 0);
+
//===--------------------------------------------------------------------===//
// Annotations Emission
//===--------------------------------------------------------------------===//
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp (revision 141335)
+++ lib/CodeGen/CGBuiltin.cpp (working copy)
@@ -951,6 +951,72 @@
return RValue::get(0);
}
+ case Builtin::BI__atomic_thread_fence:
+ case Builtin::BI__atomic_signal_fence: {
+ llvm::SynchronizationScope Scope;
+ if (BuiltinID == Builtin::BI__atomic_signal_fence)
+ Scope = llvm::SingleThread;
+ else
+ Scope = llvm::CrossThread;
+ Value *Order = EmitScalarExpr(E->getArg(0));
+ if (isa<llvm::ConstantInt>(Order)) {
+ int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
+ switch (ord) {
+ case 0: // memory_order_relaxed
+ default: // invalid order
+ break;
+ case 1: // memory_order_consume
+ case 2: // memory_order_acquire
+ Builder.CreateFence(llvm::Acquire, Scope);
+ break;
+ case 3: // memory_order_release
+ Builder.CreateFence(llvm::Release, Scope);
+ break;
+ case 4: // memory_order_acq_rel
+ Builder.CreateFence(llvm::AcquireRelease, Scope);
+ break;
+ case 5: // memory_order_seq_cst
+ Builder.CreateFence(llvm::SequentiallyConsistent, Scope);
+ break;
+ }
+ return RValue::get(0);
+ }
+
+ llvm::BasicBlock *AcquireBB, *ReleaseBB, *AcqRelBB, *SeqCstBB;
+ AcquireBB = createBasicBlock("acquire", CurFn);
+ ReleaseBB = createBasicBlock("release", CurFn);
+ AcqRelBB = createBasicBlock("acqrel", CurFn);
+ SeqCstBB = createBasicBlock("seqcst", CurFn);
+ llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
+
+ Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
+ llvm::SwitchInst *SI = Builder.CreateSwitch(Order, ContBB);
+
+ Builder.SetInsertPoint(AcquireBB);
+ Builder.CreateFence(llvm::Acquire, Scope);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(1), AcquireBB);
+ SI->addCase(Builder.getInt32(2), AcquireBB);
+
+ Builder.SetInsertPoint(ReleaseBB);
+ Builder.CreateFence(llvm::Release, Scope);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(3), ReleaseBB);
+
+ Builder.SetInsertPoint(AcqRelBB);
+ Builder.CreateFence(llvm::AcquireRelease, Scope);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(4), AcqRelBB);
+
+ Builder.SetInsertPoint(SeqCstBB);
+ Builder.CreateFence(llvm::SequentiallyConsistent, Scope);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(5), SeqCstBB);
+
+ Builder.SetInsertPoint(ContBB);
+ return RValue::get(0);
+ }
+
// Library functions with special handling.
case Builtin::BIsqrt:
case Builtin::BIsqrtf:
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp (revision 141335)
+++ lib/Serialization/ASTReaderStmt.cpp (working copy)
@@ -774,6 +774,25 @@
E->RParenLoc = ReadSourceLocation(Record, Idx);
}
+void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) {
+ VisitExpr(E);
+ E->setOp(AtomicExpr::AtomicOp(Record[Idx++]));
+ E->setPtr(Reader.ReadSubExpr());
+ E->setOrder(Reader.ReadSubExpr());
+ E->setNumSubExprs(2);
+ if (E->getOp() != AtomicExpr::Load) {
+ E->setVal1(Reader.ReadSubExpr());
+ E->setNumSubExprs(3);
+ }
+ if (E->isCmpXChg()) {
+ E->setOrderFail(Reader.ReadSubExpr());
+ E->setVal2(Reader.ReadSubExpr());
+ E->setNumSubExprs(5);
+ }
+ E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
+ E->setRParenLoc(ReadSourceLocation(Record, Idx));
+}
+
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements
@@ -2010,6 +2029,10 @@
case EXPR_ASTYPE:
S = new (Context) AsTypeExpr(Empty);
break;
+
+ case EXPR_ATOMIC:
+ S = new (Context) AtomicExpr(Empty);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp (revision 141335)
+++ lib/Serialization/ASTWriterStmt.cpp (working copy)
@@ -736,6 +736,21 @@
Code = serialization::EXPR_GENERIC_SELECTION;
}
+void ASTStmtWriter::VisitAtomicExpr(AtomicExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getOp());
+ Writer.AddStmt(E->getPtr());
+ Writer.AddStmt(E->getOrder());
+ if (E->getOp() != AtomicExpr::Load)
+ Writer.AddStmt(E->getVal1());
+ if (E->isCmpXChg()) {
+ Writer.AddStmt(E->getOrderFail());
+ Writer.AddStmt(E->getVal2());
+ }
+ Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+}
+
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements.
//===----------------------------------------------------------------------===//
More information about the cfe-commits
mailing list